专业书籍精读 · Google SRE · 第 18 章
Site Reliability Engineering · Ch 18 · Google · 2016
你在双十一零点下单没卡住,背后有一件很不浪漫的事:几个月前就有人在算「到那天要准备多少台机器、摆在哪几个机房」。这件事叫容量规划。Google SRE 这本书的第 18 章,讲的就是他们怎么把这件苦活交给了一个程序。
整本书都在讲「怎么把线上系统运维好」,只有这一章画风突变:它讲的是运维团队自己去写一款正经软件产品。听着像不务正业——救火队为什么要去开工厂?答案是,有些苦活你手工干一遍要一周,干完就过期了;只有把它变成软件,这一周的力气才会攒下来。
过去的做法是一张巨大的表格:这个服务在这个机房放多少、那个服务在那个机房放多少,一格一格填出来,再拉一圈人开会签字。麻烦在于,这张表记的是结论,不是理由。只要有一个前提变了——预测的用户涨得更快了、某批机器晚到两个月、某个上线推迟了——整张表就得重填一遍,之前那一周白干。人一累,就干脆往多了报,反正多买总比不够强。钱就这么烧掉了。
这一章的主意其实很朴素。你请人装修,与其说「客厅装三盏灯」,不如说「客厅要够亮、开关在门口、总价不超过五万」。前一种一旦房子换了就得重说,后一种换了房子,要求一个字都不用改,方案自己重算。
Google 就是这么干的:不再交「A 机房要 50 台」这种答案,而是把一堆条件写下来交给程序——这个服务要能扛住预计的用户量、坏掉一个机房还得留两份备份、得离用户近、总花销越小越好。剩下的交给一个会解题的程序:它把所有条件当成必须同时满足的规矩,在里面挑一个最省钱的摆法。前提一变,重跑一遍就行,几分钟出新方案,没人需要再填表。
有一句老实话:条件写漏了,程序不会提醒你。它只会在你没写清楚的地方,给你一个最省钱的答案——你忘了说「要留备份」,它就真的一份都不留。所以人的活并没有消失,只是从「填表格」变成了「把要求想清楚」。
与其反复手算「要多少台机器」,不如把为什么要这么多写清楚交给程序去算。答案会过期,条件不会。而运维团队之所以值得自己写这种软件,是因为只有天天用它的人,才知道条件该怎么写。
想进到具体机制、记号和示意图? → 切到精读版
你以为 SRE 写软件是为了少干点活,其实是为了让「运维」这件事第一次有了能复利的产出物。本章是全书唯一一章不讲怎么运维,而讲运维团队怎么造产品:以 Google 内部的容量规划工具 Auxon 为案例,论证把「人手拍出资源数字」换成意图式容量规划(intent-based capacity planning)——工程师声明约束与目标,求解器算出分配方案。
本章在全书第 III 部分「实践(Practices)」的中段:上承 Ch17「为可靠性做测试」,下启 Ch19–20 的前后端负载均衡。它在结构上是个异类——前后左右都在讲「怎么把线上顶住」,只有它在讲「SRE 团队怎么产出软件」。真正与它咬合的是 Ch5「消除杂务」与 Ch1 那条 50% 上限:本章相当于回答「省下的那 50% 拿去干嘛」。
传统容量规划是一条四步循环:收集需求预测 → 制定分配计划 → 评审签字 → 部署配置资源。它的产物是一张具体到数字的大表:「服务 Foo 在集群 X 要 50 核、Y 要 30 核」。
问题在于,这张表存的是结论,不是推理过程。一旦任何输入变动——预测上调、某批机器交付延期、某个依赖服务变重、某个发布推迟一个季度——整张表都得重算一遍,而算它靠的是电子表格加一圈跨团队对齐,一次迭代动辄数天到数周。书里把这个毛病叫脆弱(brittle):不是慢,是每次变动的成本都等于从头再来一次。
后果有两个方向。一是计划做完就过期,团队索性按最坏情况超配,钱烧在闲置机器上;二是工作量随服务数线性增长——量级上,一个中等服务铺在几十个集群、依赖十几个下游,人工要维护的格子就是几百上千个,再乘服务数。这恰好逐字命中 toil 的定义。
核心概念是意图(intent):驱动这个计划成立的需求与约束本身,而不是它算出来的数字。传统计划相当于只交付二进制、扔掉源码;意图式交付源码,二进制随时可重新编译。书里用一道阶梯说明「意图化」是连续光谱,不是开关:
| 层级 | 你交给系统的话 | 系统必须自己懂什么 | 代价 / 风险 |
|---|---|---|---|
| ① 具体资源 | 「Foo 在集群 X、Y、Z 各要 50 核」 | 什么都不用懂,照办即可 | 最脆:集群一换、预测一改就全废 |
| ② 放宽位置 | 「Foo 在 A 区任意 3 个集群共要 50 核」 | 哪些集群在 A 区、还有没有余量 | 量仍是人拍的,需求涨了还得手动改 |
| ③ 声明目标 (书中的甜点) | 「让 Foo 扛住 A 区的预测需求,并保持 N+2」 | 需求→资源的换算系数、依赖图、冗余语义 | 换算系数错了,错误会被放大到全局 |
| ④ 声明可靠性 | 「让 Foo 跑到 99.999% 可用」 | 可靠性与资源之间的完整映射 | 这层映射至今不成熟,书里认为落不了地 |
这张阶梯的判断很实在:第 ③ 级是甜点——抽象到足以让机器接手,又具体到能真的求解。第 ④ 级听起来最美,但「五个九」要翻译成「多少核、摆在哪」中间缺的环节太多,本章明确把它列为尚不可行的方向。这也是全章最值得带走的一条判据:把意图抬高到「目标 + 冗余」那一层就停,别追求一句话解决所有问题。
光说「声明意图」是空话,本章把它拆成三个必须提供的输入,缺一个系统就转不起来:
Auxon 是 Google SRE 自己写的容量规划工具,本章拿它作全章唯一的案例。它的形状是一条标准的「编译 + 求解」流水线:
minimize Σ price·alloc,受约束于「每个集群的用量不超过供给」「每个服务的份数 ≥ 需求所需 + 2」这类不等式;alloc 必须取整数,因为副本数不能是 2.7 个。这句话的白话版是:把所有硬性要求写成不等式,再挂一个「越便宜越好」的目标,让求解器在巨大的可能空间里搜一个最优摆法。为什么这样设计?关键在两个性质。第一,输入变了只需重跑,人不必重算,一次迭代从数周压到分钟级。第二,无解时求解器能指出是哪条约束卡住——这比一张算不出来的表格有用得多,它把「资源不够」这个模糊结论变成了「A 区的 N+2 和当前供给互斥」这种可谈判的事实。
诚实的代价:MIP 是 NP 难问题,规模一大就没法保证在可接受时间内求到全局最优,因此实际使用中要接受近似解、按区域分解问题。本章对此不回避——容量规划本来就是在不确定的预测上做决策,一个快速得到的近似解,胜过一个精确但过期的答案。
本章的另一半主张是组织层面的:这类软件应当由 SRE 团队自己产出。理由不是「没人帮我们写」,而是三条结构性优势——SRE 既是开发者又是用户,反馈回路最短;他们手上握着外部工具厂商拿不到的生产环境领域知识(真实的依赖、真实的失效模式、真实的采购约束);而且工程产出让团队价值不再随服务数线性堆人。
顺带解决人的问题:一条正经的软件工程产出线,给了 SRE 不靠转岗的成长路径。但本章同时给了硬约束:不要降低标准——这些软件在替生产做资源决策,必须按产品级要求做(设计文档、测试、明确的负责人与支持承诺),而不是「内部工具随便写写」。
最容易搞混的一组概念,先钉死:自动扩缩(autoscaling)不是容量规划。自动扩缩在分钟级对已有机器做再分配,容量规划在季度级决定「要不要买、买多少、摆哪里」。前者解决不了「机器还没到货」,后者也追不上午高峰。两者是不同时间尺度上的两件事,谁也替代不了谁。
| 你的处境 | 建议 | 为什么 | 诚实的代价 |
|---|---|---|---|
| 服务少、部署点少 (十个以内格子) | 别造,电子表格够用 | 格子数少到人脑能一次装下,求解器的价值抵不上维护成本 | 规模长起来时会晚一步,要留好迁移余地 |
| 纯云上、按需扩容 容量不稀缺 | 别造,用自动扩缩 + 成本看板 | 「买不到」这个约束不存在时,意图式最大的价值就消失了 | 账单会替你承担超配;需单独治成本 |
| 几十上百服务 × 多区域 有采购交付周期 | 值得造 | 格子数爆炸 + 前提频繁变动,正是求解器的主场 | 要投入产品级工程:设计、测试、on-call |
| 稀缺资源 (GPU / TPU 配额、专线) | 值得造 | 稀缺意味着必须显式声明优先级,否则抢占无章法 | 优先级要有人拍板,技术解决不了政治 |
| 团队没有产品级工程能力 | 先别造 | 半成品工具替生产做决策,比人工表格更危险 | 继续吃 toil,但至少可控 |
| 人工排表 | 反应式自动扩缩 | 意图式规划 | |
|---|---|---|---|
| 时间尺度 | 季度 | 秒 ~ 分钟 | 季度,可随时重算 |
| 输入变动的代价 | 数天至数周 | 不适用 | 一次重跑 |
| 能处理采购周期吗 | 能,靠人记 | 不能 | 能,供给是显式输入 |
| 主要失败模式 | 计划过期、习惯性超配 | 扩不出机器时直接挂 | 约束写漏 → 求解器帮你省掉 |
这套思想今天到处都是,只是换了名字。Kubernetes 的声明式 API(你写期望状态,控制器负责收敛)、Terraform 的期望状态模型、各家云的预留实例规划器,骨子里都是「交条件、别交步骤」;区别只在于 Auxon 把目标函数显式写成「总成本最小」,并真的塞了个数学求解器进去。
面试里的用法很具体:被问「你怎么做容量规划」,先反问意图在哪一层——「按去年峰值乘 1.5」和「声明 N+2 让系统自己算」,背后是完全不同的组织成熟度;再把「自动扩缩 ≠ 容量规划」讲清楚,基本就赢了一半。
① 一句话:全书唯一一章讲「运维团队怎么造产品」,以容量规划工具 Auxon 为案例。
② 旧世界的病:传统容量规划交付的是数字而非理由,前提一变就得从头再算——脆弱,且工作量随服务数线性涨,正中 toil 定义。
③ 核心想法:意图式容量规划——声明需求与约束,让求解器算分配;答案会过期,条件不会。
④ 意图阶梯四级:指定集群核数 → 指定区域总量 → 声明需求 + N+2(甜点) → 声明可靠性目标(书中判定落不了地)。
⑤ 意图必须包含三样:依赖图、需求→资源的换算系数、优先级。缺优先级,无解时你只会得到「无解」。
⑥ Auxon 的形状:五路输入 → 配置语言编译成约束 → 混合整数规划求「满足约束下成本最小」→ 分配计划;不可行时能指出卡在哪条约束。
⑦ 关键分辨:自动扩缩 ≠ 容量规划,时间尺度差五个数量级,谁也替代不了谁。
⑧ 为什么该 SRE 自己写:既是开发者又是用户、独占生产领域知识;但不能降低标准,它在替生产做决策。
⑨ 最大的坑:求解器只优化你写下来的东西,没写进约束的一定会被省掉;换算系数是安静的单点错误源。
⑩ 今天的回响:Kubernetes 声明式 API、Terraform 期望状态、云上预留规划器,以及 GPU 配额时代——同一套思想,换了资源类型。