☰
第一章:可靠、可扩展与可维护的应用系统
2026/9/28 18:08:29 网站建设 项目流程

第一章:可靠、可扩展与可维护的应用系统

这一章是全书的总纲。Kleppmann 不讨论任何具体技术,而是先确立评价一切数据系统的三个基本维度:可靠性、可扩展性、可维护性。后续每一章的技术权衡,最终都可以归结为在这三者之间的取舍。


一、为什么需要这三个维度

现代应用系统早已不是"一台机器跑一个程序"的形态。一个典型系统可能包含:

  • 数据库(存储状态)
  • 缓存(加速读取)
  • 搜索索引(支持全文检索)
  • 消息队列(异步解耦)
  • 批处理框架(离线分析)

这些组件通过网络连接,运行在多台机器上。系统一旦复杂,就会面临三类根本问题:

  1. 出错时怎么办?→ 可靠性
  2. 数据量/流量增长时怎么办?→ 可扩展性
  3. 长期维护和演化怎么办?→ 可维护性

这三个问题,构成了全书所有讨论的出发点。


二、可靠性(Reliability)

1. 定义

系统在出现故障(fault)时,仍能继续正确工作。

这里有一个关键区分:

术语含义例子
故障(fault)系统的一部分偏离正常状态一块硬盘坏了、一个进程崩溃
失效(failure)系统整体停止提供服务整个数据库不可用

可靠性高的系统,不是不会出故障,而是故障不会升级为失效。这就是所谓的"容错"(fault-tolerant)或"韧性"(resilient)。

2. 故障的三种来源

Kleppmann 把故障分为三类,这个分类贯穿全书:

(1)硬件故障

  • 硬盘损坏、内存位翻转、电源故障、网络中断
  • 传统做法:冗余(RAID、双电源、备用机器)
  • 现实:在大规模集群中,硬件故障是常态而非例外。Google 的统计显示,同时有数千块硬盘在坏。
  • 趋势:从"单机高可靠"转向"软件层面容忍多机故障"

(2)软件故障

  • 系统性 bug、配置错误、级联失效
  • 特点:跨节点相关——一个 bug 可能同时击垮所有副本
  • 例子:2012 年某公司因一个配置错误导致全网瘫痪;闰秒 bug 导致多系统同时崩溃
  • 难点:软件故障没有"冗余"能直接解决,因为所有副本跑的是同一份代码

(3)人为错误

  • 运维误操作、配置失误、代码逻辑错误
  • 统计上,人为错误是导致系统失效的首要原因
  • 应对策略:
    • 设计能最小化犯错机会的接口(如"安全默认值")
    • 提供沙箱环境测试
    • 快速回滚机制
    • 完善的监控与遥测

3. 可靠性的价值

  • 对用户:数据不丢失、服务不中断
  • 对企业:声誉、收入、合规
  • 对工程师:可靠性是可以被设计的,而不是靠运气

三、可扩展性(Scalability)

1. 定义

系统应对负载增长的能力。

关键点:"可扩展"不是一个二元属性,而是一个动态问题。不能简单说"系统 X 可扩展",而要说"系统 X 在负载从 A 增长到 B 时,用什么手段应对"。

2. 第一步:描述负载

在讨论扩展之前,必须先量化负载。不同系统的负载参数不同:

  • Web 服务:每秒请求数(RPS)
  • 数据库:读写比例、缓存命中率
  • 社交网络:粉丝数分布(幂律分布,少数用户有海量粉丝)
  • 聊天系统:消息发送速率、在线用户数

关键洞察:平均值会骗人。必须看分布,尤其是尾部。

3. 第二步:描述性能

两个核心指标:

(1)吞吐量(Throughput)

  • 单位时间处理的请求数/数据量
  • 适合批处理、消息队列等场景

(2)响应时间(Response Time)

  • 从发出请求到收到响应的时间
  • 注意:响应时间不是一个固定值,而是一个分布

百分位数(Percentile)——本章最重要的概念之一:

  • p50(中位数):一半请求快于此值
  • p95、p99、p999:尾部延迟
  • 为什么关注尾部?
    • 尾部延迟直接影响用户体验(一个用户可能同时发多个请求,只要一个慢就整体慢)
    • 尾部延迟往往由排队引起,而排队是系统过载的早期信号
  • 尾延迟放大(Tail Latency Amplification):如果一个用户请求需要调用 100 个后端服务,只要 1 个慢,整体就慢。所以 p99 的 1% 会变成用户侧的 63%。

实践建议:

  • 监控 p95/p99,而非只看平均值
  • 用直方图而非平均值来聚合延迟
  • 在高负载下,尾部延迟会急剧恶化

4. 第三步:应对负载增长

两种基本策略:

(1)垂直扩展(Scaling Up)

  • 换更强的机器(更多 CPU、内存、磁盘)
  • 优点:简单,无需改代码
  • 缺点:成本非线性增长,有物理上限

(2)水平扩展(Scaling Out)

  • 增加更多机器,分布式处理
  • 优点:理论上无上限,成本线性
  • 缺点:复杂性剧增(分区、复制、一致性)

Kleppmann 的核心观点:

没有万能的"可扩展架构"。适合 10 万用户的架构,未必适合 1000 万用户。可扩展性是针对特定负载的,需要根据实际访问模式来设计。

例子:

  • 读多写少 → 加缓存、加读副本
  • 写多读少 → 分区、LSM-Tree 存储
  • 复杂查询 → 列式存储、预聚合

四、可维护性(Maintainability)

1. 定义

系统在长期运行中,能被团队高效地理解、修改、扩展和运维。

Kleppmann 指出:软件的大部分成本不在初始开发,而在持续维护。维护包括:

  • 修复 bug
  • 适应新需求
  • 迁移到新平台
  • 应对新负载
  • 修复技术债务

2. 可维护性的三个设计原则

(1)可运维性(Operability)

让运维团队能轻松保持系统运行。

具体包括:

  • 提供良好的监控与日志
  • 支持自动化部署与配置
  • 避免依赖特定机器的"雪花服务器"
  • 提供清晰的文档与操作手册
  • 支持滚动升级、回滚

(2)简单性(Simplicity)

降低系统的复杂度,让新工程师能快速理解。

复杂性的表现:

  • 状态空间爆炸
  • 隐式依赖
  • 命名混乱
  • 过度抽象

应对手段:

  • 抽象:好的抽象能隐藏实现细节,如 SQL 隐藏了存储引擎
  • 消除偶然复杂性:区分"本质复杂性"(问题本身难)和"偶然复杂性"(工具/设计导致的难)
  • 模块化、清晰的接口

(3)可演化性(Evolvability)

让系统能适应需求变化。

也称为"可扩展性"(extensibility)或"可修改性"(modifiability)。关键点:

  • 需求永远在变,系统必须能跟着变
  • 数据模型、接口、协议都要支持演化
  • 这与第四章"编码与演化"直接呼应

五、本章的核心思想总结

维度核心问题关键概念应对手段
可靠性出错时能否继续工作?故障 vs 失效冗余、隔离、快速恢复
可扩展性负载增长时能否应对?百分位数、尾延迟垂直/水平扩展、针对性设计
可维护性长期能否高效维护?可运维、简单、可演化抽象、自动化、良好接口

三个贯穿全书的底层判断:

  1. 没有免费的午餐:可靠性、可扩展性、可维护性之间经常需要权衡。
  2. 没有万能方案:所有技术选型都必须结合具体负载和场景。
  3. 复杂性是最大的敌人:好的系统设计,本质上是不断对抗复杂性的过程。

六、这一章在全书中地位

第一章确立了全书的"价值坐标系":

  • 后面讲复制、分区、事务、共识时,每个技术选择都要回答:“它对可靠性、可扩展性、可维护性分别意味着什么?”
  • 例如:单主复制提高了一致性(可靠性),但牺牲了写可扩展性;无主复制提高了可用性,但增加了冲突处理的复杂性(可维护性下降)。

一句话概括本章:

数据系统的设计,本质上是在可靠性、可扩展性、可维护性这三个维度上,针对具体负载和场景,做出清醒的、有意识的权衡。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询