非功能性需求 (NFR) 与功能性需求一样重要,因为它们定义了系统的质量和操作参数。
功能性需求指定了软件产品应该做什么(例如,“用户必须能够登录”)。然而,非功能性需求定义了它在现实条件下必须如何完成这些任务(例如,“在峰值负载下,登录过程应在两秒内响应”或“所有用户凭证必须加密并安全存储”)。
功能性需求和非功能性需求共同为构建优秀的软件系统奠定了基础。
在本主题的第 1 部分中,我们还研究了非功能性需求的权衡以及这些需求对架构的影响。第 1 部分的一些关键学习点如下:
非功能性需求决定系统在可扩展性、响应时间、性能、安全性等方面的性能,确保它满足质量标准和用户超越功能性的期望。
功能需求关注系统应该做什么,而非功能需求定义系统在现实条件下的运行情况。
优化一个 NFR(例如性能)可能会对其他 NFR(例如可维护性)产生负面影响,因此需要根据项目目标和约束采取平衡的方法。
非功能性需求(如可扩展性和可用性)对架构选择影响很大。例如,选择微服务以实现高可用性,或选择基于插件的设计以实现可修改性。
在本文中(第 2 部分),我们将进一步探讨构建系统时应考虑的一些最重要的 NFR。
需要考虑的关键 NFR
设计应用程序时应考虑的一些关键非功能性要求如下:
响应时间/延迟
响应时间(通常称为延迟)是用户操作(例如,单击按钮或发出 API 请求)与系统相应响应(例如,呈现下一页或返回数据)之间的间隔。
参见下图:
简单来说,就是用户或客户端等待系统处理请求并提供结果的时间。
测量延迟的一些关键指标如下:
平均响应时间(平均值):系统响应请求的平均时间,通过将所有响应时间相加并除以请求数计算得出。这对于了解系统性能的总体情况很有用,但如果存在极端异常值,则可能会产生误导。
第 95 或第 99 百分位响应时间:测量 95% 或 99% 的请求完成的响应时间,突出显示最坏的性能场景。它有助于识别影响一小部分但关键用户的异常值和峰值负载条件。
首字节时间 (TTFB):客户端发出请求和收到服务器响应首字节之间的时间。此指标对于 Web 应用程序至关重要,因为它反映了服务器处理时间和网络延迟,影响感知速度和 SEO 排名。
对系统延迟有重大影响的因素如下:
网络开销:繁忙的网络会导致数据包延迟,并且可能由于数据包丢失而导致重新传输。
物理距离:跨越较大地理距离的数据传送会遭遇更长的往返时间。
协议开销:加密或 TLS 等安全协议为握手和数据编码/解码增加了额外的步骤。
应用程序逻辑:复杂的计算或大型循环会增加 CPU 使用率,导致响应变慢。处理许多同时发生的请求也会导致线程争用或排队延迟。
查询复杂性:优化不佳的查询或缺少索引会减慢数据检索速度并增加延迟。
数据库锁:对同一行/表的并发写入或更新可能会导致阻塞或死锁。
多个服务调用:多个内部服务调用(在微服务架构中)可能会累积延迟。此外,如果系统依赖于外部服务,它们的响应时间也会增加。
吞吐量
吞吐量是指系统在给定时间内处理的交易、请求或操作的数量(例如每秒请求数、每分钟数据库交易数等)。
例如,如果一个 API 每秒处理 5,000 个请求,这就是其在当前条件下的吞吐量。
衡量吞吐量的关键指标如下:
每秒请求数 (RPS) :API 或服务器每秒处理的请求数。
每秒交易次数(TPS):常见于数据库和财务系统。
每秒查询数(QPS):用于衡量数据库处理读/写查询的能力。
带宽利用率:衡量正在使用的网络容量。
吞吐量衡量的是系统容量,而不是单个请求的速度。
响应时间短并不一定意味着吞吐量高。如果系统处理请求很快但无法同时处理多个请求(由于 CPU、内存或数据库限制),吞吐量仍然会很低。通常,高吞吐量系统旨在处理许多并发用户,同时保持可接受的响应时间。
一些潜在的吞吐量瓶颈如下:
CPU和内存限制:如果服务器的 CPU 使用率达到 100%,则无法有效处理其他请求。例如,高流量的电子商务网站可能会遇到用户激增的情况,导致服务器负载过大并降低吞吐量。
数据库性能:查询速度慢、锁定过多或索引未优化可能会限制数据库事务吞吐量。例如,当太多事务尝试更新同一帐户余额时,处理付款的系统就会出现死锁。
I/O 瓶颈(磁盘和网络):如果磁盘速度慢,则写入磁盘可能会成为瓶颈。
并发限制:线程池、连接池或后端服务可能会限制同时处理的请求数量。
速率限制和节流:许多外部服务都会施加请求限制以防止滥用。例如,天气 API 可能每分钟只允许 1K 个请求,从而限制了应用可以同时服务的用户数量。
资源利用
资源利用率是指系统如何有效地利用其可用的硬件和基础设施,特别是 CPU、内存、输入/输出 (I/O) 和网络带宽。
当利用率达到平衡时,系统可以高效地执行任务,而不会过度配置(浪费资源)或配置不足(造成瓶颈)。在云或虚拟化环境中,高效利用意味着更低的运营成本(我们为更少或更小的实例付费)和更好的性能。
同时,它支持可扩展性,因为最佳利用的系统可以扩展或收缩其资源而无需大量开销。
资源利用率低会以多种方式降低系统性能和可用性。
例如,如果 CPU 使用率持续保持在 100%,应用程序可能会变得非常缓慢或者无响应。
如果内存不足,关键进程可能会被迫进入交换空间,从而导致系统严重减速或崩溃。
如果 I/O 操作很慢(例如由于磁盘或存储网络饱和),请求就会堆积起来,从而增加响应时间。
同样,网络带宽限制也会阻碍数据传输,尤其是在微服务架构或数据量大的应用程序中,导致超时和请求失败。
在所有这些情况下,最终用户都会经历更长的等待时间、更低的可靠性,甚至可能完全中断服务。这凸显了有效利用资源对现代软件系统如此重要的原因。
可扩展性
可扩展性是系统在不牺牲性能或可靠性的情况下处理不断增加的工作负载的能力。
它确保随着用户需求的增长,无论是请求数量、数据量还是交易率,系统都能以可控且经济高效的方式扩展容量。
下图显示了如何比较两个系统的可扩展性。
开发人员可以使用两种主要类型的扩展方法:
水平扩展(Scale Out):这涉及添加更多机器或节点以将工作负载分配到多个实例中。例如,在云环境中使用自动扩展组并将大型数据集拆分到多个数据库(分片)中,每个数据库处理一部分总体负载。
垂直扩展(向上扩展):这涉及通过添加更多 CPU、内存或存储来提高现有机器的性能。例如,从小型 VM 实例迁移到具有更多核心和 RAM 的大型 VM 实例。
通过水平扩展,我们可以不断增加容量。这通常具有更高的容错能力,因为一个节点的故障不会导致整个系统崩溃。但是,它可能会带来编排复杂性和网络开销增加。
另一方面,垂直扩展很容易实现,现有应用程序可能只需要进行最少的重新配置。但是,它在硬件约束方面有上限,当需要进行重大升级时,成本会变得昂贵。
容量
容量是指系统在性能或可靠性开始下降之前可以处理的最大工作量。可以使用并发用户、交易或数据存储等参数来衡量。
一旦系统超出此限制,延迟可能会激增,吞吐量可能会下降,并且用户可能会遇到超时或错误。
这使得容量规划成为一项重要活动,原因如下:
防止服务中断:超出其容量的系统可能崩溃或变得非常缓慢,从而导致收入损失和用户信任受损。
确保流畅的用户体验:用户期望一致的响应时间和可靠性。足够的容量可确保应用程序在正常负载和峰值负载下保持高性能。
优化成本:过度配置会浪费资源,而配置不足则会损害性能。容量规划旨在在性能需求和预算限制之间取得平衡。
支持可扩展性:通过了解容量阈值,团队可以使用自动扩展、集群或缓存等技术设计可扩展的架构。
但如何估计和规划容量呢?
以下是一些提示:
检查典型使用情况、高峰期(例如假日销售)和业务周期(每日、每周和每月)。使用每秒平均请求数、峰值并发用户数或每日交易量等指标来确定典型负载。
模拟用户流量稳步增加直到系统出现压力迹象。
查看过去的流量高峰、销售期或季节性波动。通过推断增长率并叠加已知业务事件(如新功能发布和营销活动)来估计未来需求。
可用性
可用性衡量系统在给定时间段内的运行频率和可供用户访问的频率。
实际上,高可用性系统即使在意外故障或维护时段下也能将停机时间降至最低。此外,如果发生中断,这样的系统可以快速恢复。可靠性与可用性密切相关,侧重于系统在一段时间内无错误地执行其预期功能的能力。
即使将可用性提高百分之几,也可以显著减少停机时间,但会增加成本和复杂性。可用性通常以每年的百分比表示,相当于特定的停机时间量。
常见目标包括:
99.9%(“三个九”)
停机时间:每年约 8.76 小时不可用
用途:通常适用于许多 Web 应用程序或企业内部系统
99.99%(“四个九”)
停机时间:每年约 52.6 分钟
用途:通常以关键任务服务、电子商务平台和金融应用程序为目标
99.999%(“五个九”)
停机时间:每年约 5.26 分钟
用途:高风险场景,例如应急响应系统或大型金融交易处理器。
下表显示了各种可用性百分比及其停机时间数字:
除了特定的架构模式外,提高可用性很大程度上取决于监控和实施自动故障转移机制。一些基本技巧如下:
使用 Prometheus、Grafana 或 CloudWatch 等工具跟踪 CPU、内存、磁盘使用情况和响应时间。
定期验证服务端点以检测故障的早期迹象。当出现故障时,Kubernetes 或类似平台可以重新启动容器或将工作负载转移到健康节点,从而最大限度地减少停机时间。
自动通知(电子邮件、短信、Slack)向值班团队告知异常或中断情况。
自动将请求从不健康的节点或数据中心转移出去。
弹性和容错
弹性是指系统在遇到错误或意外情况(无论是服务器崩溃、网络中断还是数据中心中断)后恢复的能力。弹性系统在组件发生故障时可能会暂时降低性能或禁用某些功能,但最终会恢复正常运行。
相比之下,容错关注的是系统在组件发生故障时仍能正常运行的能力,理想情况下不会出现明显的停机或服务降级。
换句话说,弹性侧重于故障后的恢复,而容错则旨在在发生故障时继续无缝运行。这两个概念都有助于确保强大、用户友好的体验,但处理故障的方法不同。
在分布式系统中,故障是不可避免的,无论是由于网络链接速度慢、进程崩溃还是数据中心损坏。采用“一切都会失败”的思维模式可以鼓励开发人员考虑当服务、数据库分片或外部 API 不可用时会发生什么。例如:
如果推荐服务出现故障,系统可能会提供后备建议或只是隐藏该部分,而不是阻止整个用户体验。
当主数据库无法访问时,从副本或缓存数据存储中读取以维持部分功能。
防止调用服务无限期等待并引发连锁故障反应。
公司投入大量资金来增强系统的弹性和容错能力。
例如,Netflix 使用 Chaos Monkey 工具推广了弹性工程,该工具会随机终止生产环境中的实例。通过这种方式,团队可以了解哪些服务或组件不适合处理意外关闭。此外,定期进行混沌实验可确保新功能和部署保持弹性。
灾难恢复
灾难恢复 (DR) 是指组织在发生硬件故障、自然灾害或网络攻击等灾难性事件后用于恢复关键系统和数据的策略和流程。其主要目标是最大限度地减少停机时间和数据丢失,确保业务连续性。
两个关键指标推动着 DR 规划:
恢复时间目标 (RTO):灾难发生后系统或服务可以离线的最大可接受时间。例如,如果 RTO 为 4 小时,则组织必须在发生重大中断后 4 小时内完全恢复运营。较短的 RTO 需要更复杂的恢复解决方案(例如自动故障转移),这可能会增加成本和复杂性。
恢复点目标 (RPO):以时间为单位测量的最大可接受数据丢失量。如果 RPO 为 1 小时,则我们必须能够恢复灾难发生前至少 1 小时的所有数据。更严格的 RPO 需要更频繁或实时的数据复制,从而影响存储、带宽和基础设施选择。
耐用性
耐用性是指保证数据一旦提交或保存,即使系统发生崩溃、断电或其他故障,仍可访问且完整。
在事务系统(例如数据库)中,持久性可确保成功完成的事务不会“回滚”或丢失。简而言之,一旦系统确认数据已存储,它就应该是永久的,并且在正常故障条件下可恢复。
下图显示了数据库中的持久性概念。
确保耐用性的一些常见策略如下:
复制:在不同的服务器或数据中心存储相同数据的多个副本。即使一个节点或位置发生故障,副本也可以提供最新数据。在多主复制设置中,每个节点都会保留数据的近乎实时的副本,因此不存在单点故障。
预写日志:在更改主数据文件之前,系统会将预期更改写入日志或日记。如果系统在操作过程中出现故障,它可以使用此日志“重放”或回滚更改以保持一致性。
快照:这涉及定期捕获数据库或存储系统在某一时间点的整个状态。它允许恢复到已知的一致状态,尤其是在后来发现损坏或意外删除时。
一致性在持久性中也发挥着重要作用。在强一致性系统中,每次读取操作都反映最近的写入,确保数据在所有节点上始终保持一致。这通常会增强感知到的持久性。一旦数据被写入,它就会被快速复制并随处可见。
另一方面,在最终一致性场景中,写入会随时间传播。不同的副本可能会看到不同的数据,直到它们收敛,从而产生短暂的窗口,如果节点在同步之前发生故障,数据可能会丢失或被覆盖。在最终一致性系统中,可能会存在短暂的数据“间隙”,即并非所有副本都具有最新数据。除非采取适当的保护措施,否则在该间隙期间发生崩溃可能会导致最新数据丢失。
一致性
分布式系统中的一致性是指如何在多个节点或副本之间保持数据同步,确保读取反映特定规则下最新的写入。
一致性模型有两种类型:
强一致性:写入操作完成后,任何后续读取操作(对系统中的任何节点)都将返回最新的更新值。这种方法对于金融交易、库存管理或任何需要即时、一致数据以确保正确性的领域都很重要。传统的关系数据库通常力求实现强一致性。
最终一致性:更新会随时间传播。不同的副本可能会暂时看到不同的状态,但只要有足够的时间(假设没有新的写入),所有副本都会收敛到相同的状态。它通常用于社交媒体源、内容缓存或分析平台,在这些平台中,为了获得更高的可用性和可扩展性,可以接受短时间内的陈旧数据。许多 NoSQL 系统(如 Amazon DynamoDB 和 Cassandra)默认采用最终一致性模型。
根据应用程序的需求(严格的正确性或高可扩展性),开发人员可以选择不同的一致性模型。
Eric Brewer 的 CAP 定理指出,在存在网络分区的情况下,分布式系统必须在一致性和可用性之间做出选择。它无法完全保证两者。
下图是 CAP 定理的图形表示:
由于分布式系统中网络分区是不可避免的,开发人员经常需要做出权衡,例如:
CP 系统:选择一致性和分区容忍度而不是可用性。如果系统无法保持一致性,则可能会在分区期间拒绝请求。
AP 系统:选择可用性和分区容错性,而不是严格的一致性。系统仍可运行,但可能会在分区期间提供稍微过时的读取。
模块化
模块化是一种设计原则,涉及将大型代码库分解为较小的、独立的单元(模块或组件)。
它通过多种方式使大型代码库受益:
维护和更新更轻松:每个模块都承担明确定义的职责,从而降低了修改特定功能时出现意外副作用的可能性。这意味着无需更改整个系统即可升级、重构或替换模块。
减少耦合:最小化共享依赖项或全局状态的数量可防止一个模块的更改破坏另一个模块。每个模块都可以通过最少的外部组件模拟进行单元测试。
然而,模块化程度的提高也可能存在缺点:
部署复杂性:管理多个模块或服务通常需要更复杂的 CI/CD 管道、容器编排和监控。
网络延迟:在基于服务的环境中,服务间调用会增加往返开销和潜在的故障点。
版本控制和兼容性:确保所有模块保持兼容可能具有挑战性,特别是在它们共享接口或 API 的情况下。
技能要求:开发人员、DevOps 和 QA 团队必须了解分布式系统、编排工具和高级测试策略。
一些包含模块化概念的常见架构风格如下:
微服务架构:每个微服务都是一个独立的组件,通常独立部署和扩展。
基于插件的系统:核心应用程序提供了一个用于加载插件的框架,每个插件都提供一个独立的功能或扩展。
分层架构:将系统分为多个层(例如,表示层、业务逻辑层、数据访问层)。每个层负责应用程序的特定方面
可测试性
可测试性是指通过测试验证软件系统功能和行为的难易程度和效率。测试过程可以是手动的,也可以是自动的。
高度可测试的系统通常具有组件之间清晰的边界、最小的依赖关系和定义明确的接口,因此可以轻松隔离、观察和验证各个部分。换句话说,模块化是提高系统可测试性的理想属性。
设计决策会极大地影响可测试性。
例如,依赖注入 (DI) 是提高可测试性的好方法。类或模块不是在内部创建依赖项,而是从外部源(例如 DI 框架或工厂)接收其依赖的对象。这使得在测试期间用模拟或存根替换真实依赖项变得很容易。
其次,构建系统时明确区分关注点可以提高可测试性。独立组件更易于单元测试,因为每个模块都执行一组重点任务,并且依赖于定义良好的接口。
最后,松耦合和高内聚可提高可测试性。组件之间应了解最少的信息,并处理自身内部密切相关的功能。这可降低系统某一部分发生的变化导致其他部分测试失败的风险,使系统测试更具可预测性。
一些测试的最佳实践如下:
单元测试:专注于单独验证最小的功能部分(方法、类或模块)。其目的是确保测试快速且具有确定性。
集成测试:确保模块或服务能够正确协同工作。目标是在尽可能反映生产的测试环境中测试关键组件之间的交互。
系统测试(端到端):这涉及从头到尾验证整个应用程序流程和用户场景。目的是测试真实的用户路径,包括错误处理和边缘情况。
代码质量
代码质量包括软件代码库的编写质量、可理解性和可维护性。
高质量的代码通常结构清晰,符合行业或组织标准,没有明显的缺陷,并且易于随着需求的变化而修改。确保代码质量高会在项目的整个生命周期内带来回报,影响性能、可靠性和总体开发成本。
开发人员可以牢记代码质量的一些关键方面:
可读性:这是衡量新成员或现有团队成员阅读和理解代码的难易程度的指标。通过使用有意义的变量和函数名称(例如,使用 calculateTotalPrice 而不是 calc),可以提高可读性。其他方法是保持方法和类简洁,以减少认知负担。
可维护性:这表示在不破坏现有功能的情况下,代码更新或扩展的难易程度。开发人员应致力于在类或模块内实现单一职责,并将代码组织到逻辑包或文件夹中。
编码标准:代码质量还取决于遵循编码标准,例如规定的一套样式指南、命名约定和最佳实践。命名和格式的统一性使跨团队协作更加顺畅。
可配置性
配置包含各种设置(例如,数据库连接字符串、API 密钥和功能标志),这些设置决定了软件在不同环境(例如开发、测试、登台或生产)中的行为方式。
通过将配置与代码分离,团队可以改变行为,而无需重建或重新部署整个应用程序。
保持配置分离的一些好处如下:
部署灵活性:将特定于环境的详细信息存储在代码中会强制每次环境更改(例如,从测试数据库切换到生产数据库)时发布新版本。自动化管道可以通过在部署时注入环境值(如 API 端点或日志记录级别)来减少人工干预。
维护更轻松:将设置保存在集中配置存储或文件中有助于团队快速审核和修改它们。开发人员无需搜索代码来查找环境详细信息,从而最大限度地减少了无意中将机密或生产凭据推送到版本控制的机会。
环境特定设置:测试环境可能会大量记录调试日志,而生产日志则会受到限制以节省资源。可以根据环境或用户段打开或关闭某些功能,而无需更改代码。
有助于提高系统可配置性的工具和框架的一些示例是环境变量、配置文件、功能切换和外部配置管理服务(例如 Hashicorp Vault、Consul 或 Kubernetes ConfigMaps)。
安全
安全性作为一项非功能性要求,可确保系统的数据和操作得到充分保护,免受未经授权的访问、篡改或泄露。
安全不是一次性活动。它需要持续的修补、监控、测试和合规性审查。它涉及从身份验证和授权到数据机密性、完整性和可审计性的多个方面。
需要牢记的一些关键安全注意事项如下:
身份验证:验证用户或系统的身份(例如,用户名/密码、多因素身份验证等)。
授权:控制经过身份验证的用户或系统可以做什么(基于角色或基于属性的访问)。
机密性:确保只有授权实体才能访问数据。
完整性:保护数据不被未经授权的方篡改或更改。
审计和日志记录:记录与安全相关的操作以检测或调查未经授权的活动。
安全性考虑通常需要与性能和可用性取得平衡。
加密、多因素身份验证和大量日志记录可能会增加延迟或资源利用率。此外,严格的密码策略或复杂的多因素流程可能会让最终用户感到沮丧。
一些行业(如金融和医疗保健)由于监管或声誉风险而优先考虑严格的安全性。其他行业可能倾向于易用性,但前提是用户数据仍然需要强有力的保护。
可用性
可用性描述了用户如何有效、高效且令人满意地与软件系统交互以实现他们的目标。
尽管它没有概述具体的功能行为(例如,“应用程序必须允许用户提交表单”),但它会显著影响用户体验是否令人愉悦、高效和易用。因此,可用性被归类为非功能性需求。它指定系统从用户体验的角度应如何表现,而不是它提供哪些功能。
开发人员采用可用性启发法、用户测试和 A/B 实验来提高可用性。可用的产品可以降低支持成本、提高用户满意度并建立积极的品牌认知度。
理解可用性时需要考虑的关键因素如下:
直观性:这是指用户无需大量指导或反复试验即可执行任务的程度。例如,使用标准术语清晰标记的导航菜单比使用晦涩难懂的图标或术语的导航菜单更容易理解。
可访问性:这可确保残障人士(视觉、听觉、运动或认知)可以使用该软件。例如,遵守 WCAG(Web 内容可访问性指南)以提供图像的文本替代、启用键盘导航和支持屏幕阅读器。
易学性:它是衡量新用户理解和熟练系统工作流程的速度的指标。
互操作性
互操作性是指软件系统与其他系统、API 或服务交换数据或功能的能力,无论底层平台或协议如何。
通过遵守通用标准并进行兼容性设计,开发人员可以确保更顺畅的集成、最大限度地减少返工,并最终在不同技术之间提供更具凝聚力的用户体验。
互操作性对于现代系统非常重要,原因如下:
顺畅的数据交换:使用通用语言(如 RESTful JSON、SOAP XML)的系统可以共享信息,而无需自定义、容易出错的转换。
降低集成成本:遵循既定标准(如用于身份验证的 OAuth 和用于服务定义的 OpenAPI),每次需要新的集成时,无需定制解决方案。一致的界面简化了新合作伙伴或第三方开发人员的入职流程。
面向未来:具有前向和后向兼容性的系统可以在不破坏现有集成的情况下不断发展。这对于长期存在的平台(如政府系统或大型企业)尤其重要,因为升级可能会花费高昂或造成破坏。
提高互操作性的一些技术如下:
使用版本控制构建 API:在 REST 端点中包含版本号(例如,/v1/users、/v2/users)以推出新功能而不会中断现有消费者。
采用标准协议和格式:使用广泛认可的方法(例如 JSON、XML、OAuth)使外部利益相关者能够轻松进行集成。
文档弃用政策:宣布弃用,提供迁移路径,并在最终删除之前设定合理的时间表。
验证和测试集成:维护集成测试环境和沙盒 API,以便合作伙伴可以在投入生产之前测试更改。
监控:跟踪使用模式,查看旧端点是否仍然被大量使用,以便可以在不中断的情况下管理弃用。
概括
在本文中,我们详细研究了各种非功能性需求以及如何衡量或改进它们。
一些关键的学习点如下:
响应时间或延迟是用户操作(如单击按钮或发出 API 请求)与系统相应响应(如呈现下一页或返回数据)之间的间隔。
吞吐量表示系统每单位时间处理的操作数。必须识别并优化瓶颈(CPU、数据库、I/O),以实现高容量性能。
高效利用 CPU、内存、I/O 和带宽可节省成本并获得可预测的性能,而利用率低则会导致速度变慢或中断。
水平扩展(向外扩展)可增加更多机器,而垂直扩展(向上扩展)可增加更多功能。两者都可以满足不断增长的需求,但需要在复杂性和成本方面进行权衡。
容量是系统在性能下降之前可以处理的最大负载。容量规划可确保在流量高峰期间获得顺畅的用户体验。
可用性通常用“九”来表示(99.9%、99.99% 等),并规定了冗余、监控和故障转移策略以最大限度地减少停机时间。
弹性和容错强调在发生故障时恢复和继续运行。断路器和隔墙等模式可帮助系统平稳降级,而不是崩溃。
可恢复性设定了系统必须恢复的速度。
耐用性依靠复制、日志和快照确保提交的数据即使在崩溃或断电后仍然保持持久。
强一致性保证跨节点的数据立即对齐。另一方面,最终一致性优先考虑可用性和可扩展性,但接受暂时的数据差异。
模块化是将系统分解为独立的组件,以降低复杂性、增强可维护性并促进独立测试和更新。
可测试性涉及松散耦合的设计,而依赖注入使系统更易于测试。
可读、标准化、结构良好的代码可以减少错误、提高长期性能并避免昂贵的技术债务。
在外部存储特定于环境的设置(例如环境变量)可以实现灵活、可靠的部署,并降低安全风险。
安全性涵盖身份验证、授权、机密性、完整性和审计。安全设计在性能、可用性和法规遵从性之间取得平衡。
可用性涉及直观性、可访问性和易学性。即使是很小的 UI 改进也可以大大提高用户满意度。
互操作性和兼容性确保跨系统或服务之间的无缝通信和数据交换,利用标准(REST、SOAP、OAuth)和版本控制来防止重大变化。







































