3.0

View in English

3.0 第 3 部分引言:系统

架构是指那些一旦做出就很难逆转的决策。你该如何将一个系统拆分成若干部分?这些部分之间又该如何通信?数据该如何建模?整个系统在负载和故障下又会如何表现?第 3 部分正是关于有意识地做出这些决策。在小型团队中,架构可以存在于少数几个人的脑海中,并随着开发不断演进。而在大型组织中(数百名工程师、数十个团队、系统的寿命将超过构建它们的人的职业生涯),架构就成为让所有人保持协调一致的关键所在。架构清晰时,各团队可以独立推进而不会相互冲突;架构含糊不清时,每一次跨团队依赖都会变成一场谈判,每一次事件都会变成一场考古项目。

在企业和政府领域,风险最高。税务引擎、福利平台、国家健康档案,或者银行的核心账本,这些系统生命周期长、受到严格监管、在多个部门之间共享,并且要对公众负责。你今天在耦合、数据所有权和质量属性方面做出的决策,将在未来十年甚至更长时间内限制系统的可能性。监管机构和审计人员越来越期望看到有文档记录、经得起审查的架构,并要求提供切实证据,证明可靠性、安全性、隐私性和持久性是从一开始就设计进去的,而不是事后临时加上去的。那些登上新闻头条的失败案例,往往都是架构层面的失败:门户网站在上线当天就崩溃、申报系统在截止日期临近时超时、迁移过程丢失记录或重复计数记录。

本部分首先介绍历久弥新的基础知识,接着讨论具体的结构性选择,然后深入探讨分布式、数据和规模方面的现实问题,最后以大多数大型组织实际面临的最棘手问题收尾:对他们已经在运行的系统进行现代化改造。贯穿始终的主线是:好的架构是一系列有意识的权衡取舍,而不是赶时髦的默认选择。

本部分的章节

  • 3.1 架构基础。那些经得起技术潮流考验的持久工具:质量属性(即”-ilities”)、具有架构意义的需求、适应度函数(用于守护所选架构质量的自动化测试)与演进式架构、借助 C4 模型(四个缩放层级的嵌套架构图)和 arc42(一种架构文档模板)进行的轻量级文档记录,以及结构化的权衡分析。

  • 3.2 架构风格与模式。对主要系统形态的概览,从单体架构到 微服务、带有 CQRS(命令查询职责分离,将读模型与写模型分开)和事件溯源(将状态存储为仅追加的事件日志)的 事件驱动架构、服务网格(用于服务间通信的专用基础设施层)与网关、无服务器架构,以及 六边形架构 与整洁架构;并以 康威定律(系统的结构往往会反映构建它的组织的沟通结构)为框架,指导每种风格分别适用于何种场景。

  • 3.3 分布式系统。一旦跨越网络边界就会出现的严酷现实(不可靠的网络、部分故障、没有共享时钟),以及应对这些现实的标准防御手段:一致性推理、幂等性(使某个操作可以安全地重复执行)、带退避的重试、断路器(用于停止调用出现故障的依赖项)、Saga(一系列带有补偿性撤销步骤的本地事务),以及分布式可观测性。

  • 3.4 数据架构与存储。数据如何建模、存储、保持一致,并在大规模场景下快速提供服务:主要的存储范式及各自的适用场景、多语言持久化(在同一系统中使用多种专用数据存储)、模式演进与迁移、缓存与 CDN(内容分发网络),以及负载下的事务与并发。

  • 3.5 可扩展性、性能与弹性。三种应当从一开始就设计进去、而非事后补救的独立质量:水平扩展与垂直扩展、无状态性与 分片(按某个键将数据拆分到多台机器上)、负载均衡与自动扩缩容、性能预算、弹性模式与 混沌工程,以及以 RTO(恢复时间目标)和 RPO(恢复点目标)为框架的跨区域 灾难恢复。

  • 3.6 遗留系统现代化。真正行之有效的渐进式模式:绞杀者模式(在旧系统周围逐步构建新系统,直到旧系统可以退役)和抽象分支模式(在主开发线上,通过接口替换某个组件背后的实现),此外还有遗留系统风险评估、大型机 与 COBOL(Common Business-Oriented Language,面向商业的通用语言)维护、数据迁移与双运行,以及如何抵御”大重写”的诱惑()这种诱惑正是本领域代价最高昂的失败之源。

  • 3.7 软件维护。软件生命周期中占主导地位的阶段:纠错性维护、适应性维护、完善性维护和预防性维护,程序理解与再工程,以及为可维护性而设计,从而让长期运行的系统始终能够以可承受的成本进行变更。

  • 3.8 互操作性与开放标准。设计系统时通过开放标准而非定制集成来实现互操作:技术层面、语法层面和语义层面的 互操作性,医疗健康领域的 FHIR 等领域标准,以及专有锁定所带来的成本。

  • 3.9 系统工程。端到端地对复杂系统进行工程化,通常需要将软件、硬件、人员和流程结合在一起:生命周期、需求分配与可追溯性、接口、集成,以及验证与确认。

  • 3.10 嵌入式与实时系统。面向受到严格约束的设备的软件:实时行为与确定性、RTOS(实时操作系统)或裸机固件、有限的内存与电力、硬件交互,以及安全关键标准。

  • 3.11 云架构。为云而设计,而不是简单地将数据中心”照搬上云”:服务模型与无服务器架构、作为故障域的区域与可用区、共担责任模型、托管服务与锁定之间的权衡、在多云与混合云能够证明其复杂性物有所值时采用它们,以及具备成本意识的良好架构设计。

  • 3.12 事件驱动架构与消息传递。构建通过产生事件和响应事件进行通信的系统:队列与持久化流的对比、协同式与编排式的对比、在事件溯源和 CQRS 能够物有所值时采用它们、用于分布式事务的 Saga、投递保证与幂等性,以及让异步流程保持可靠的各种模式。

  • 3.13 网络与连接。应用工程师实际会打交道的网络知识:DNS、TCP 与 HTTP 的演进、TLS 终止、负载均衡与反向代理、内容分发与边缘计算、服务发现与服务网格,以及让网络的不可靠性变得可以承受的超时、重试与断路器。

  • 3.14 多租户与 SaaS 架构。用一个软件实例服务众多客户,同时不让他们相互看到彼此,也不让彼此争抢资源:隔离性与效率之间的权衡谱系、数据分区、针对”吵闹邻居”问题的按租户配额、租户生命周期,以及成本归因。

  • 3.15 缓存与内容分发。在整个缓存层级(客户端、边缘与 CDN、反向代理、应用程序和数据存储)中,用少量的数据陈旧性换取延迟、负载和成本方面的巨大收益,同时将缓存失效与击穿防护作为一等重要的设计问题来对待。

  • 3.16 API 网关与服务网格。在 API 网关处理南北向流量(路由、身份验证、限流、组合),并通过服务网格处理东西向流量(双向 TLS、流量切换、重试、可观测性),以及判断服务网格何时能够证明其复杂性物有所值。

  • 3.17 搜索与信息检索。将搜索视为一等重要的系统,从倒排索引和相关性排序,到查询理解、分面筛选,再到向量检索与混合检索,并采用真正的相关性评估而非凭猜测行事。

本部分各章节之间的关系

这些章节按顺序层层递进、相互建立在彼此之上。第 3.1 章给出了此后每一章都会用到的词汇(质量属性与权衡分析);它所命名的各种”-ilities”,正是第 3.4 章和第 3.5 章要具体落实的内容。第 3.2 章将这些基础知识转化为具体的结构性选择,而它所支持的那些更加分布式的风格(微服务、事件驱动、服务网格)带来了第 3.3 章教你如何管理的各种成本。第 3.3 章、第 3.4 章和第 3.5 章之间彼此高度依赖:分布式带来了数据架构中的一致性与持久性决策,而分布式与数据两者共同决定了你实际能够达到的可扩展性与弹性水平。第 3.6 章则收束了这条线索,因为大多数大型组织并不是在一张白纸上构建系统:他们是在演进那些制约着前面各章所述一切选择的既有记录系统。

第 3 部分也与外部内容相互关联。第 3.2 章借助第 2.2 章的设计原则和领域驱动设计,来寻找良好的服务边界。让这些系统持续运转的运维规程位于第 9 部分:站点可靠性工程(第 9.1 章)和可观测性(第 9.2 章)正是架构弹性在生产环境中得到验证的地方。监管机构所要求的安全性与隐私属性是在本部分设计出来的,但会在第 4 部分详细展开,而第 8 部分中的平台与交付实践,则决定了一个架构能否真正由多个团队同时交付和运维。