yingjie@memoir
Skip to content

Google SRE

第六章 监控分布式系统

核心概念

监控类型

  • 白盒监控:基于系统内部指标(日志、JVM接口、HTTP统计端点)
  • 黑盒监控:模拟用户视角测试外部可见行为
  • 黄金信号:延迟、流量、错误、饱和度——用户-facing系统的四大核心指标

关键区分

维度说明
症状 vs 原因症状回答"什么坏了",原因回答"为什么"
黑盒 vs 白盒黑盒面向症状(当前故障),白盒可预测即将发生的问题

核心原则

1. 告警设计哲学

  • 每次告警都应引发紧迫感——人一天只能紧急响应几次
  • 每个告警必须可执行——不能只是机械响应
  • 每个响应需要智能——能自动化的就不该告警
  • 告警应指向新问题——重复问题需根治

2. 告警自检问题

创建规则前需确认:

  • 是否检测紧急、可执行、用户可见的问题?
  • 是否会习惯性忽略?如何避免?
  • 是否确实影响用户?(需过滤测试流量等场景)
  • 能否采取行动?紧急程度如何?能否自动化?是长期修复还是临时方案?
  • 是否重复告警

3. 避免过度复杂

  • 最常用规则应最简单可靠
  • 很少触发的配置(如一季度一次)应考虑移除
  • 未在仪表盘或告警中使用的指标应清理
  • 监控应与调试、日志分析等系统松耦合

实战教训

Bigtable案例:过度告警的代价

  • 问题:基于平均延迟的SLO被尾部延迟(最差5%请求)拖累,邮件和告警泛滥
  • 解决:暂时降低SLO目标(改用75分位延迟),禁用邮件告警
  • 结果:获得喘息空间修复底层问题,而非疲于应对战术问题

Gmail案例:脚本化响应的危险

  • 问题:Workqueue调度器故障导致数千任务告警,人工"轻推"调度器成为常态
  • 矛盾:自动化 workaround vs 担心延迟真正修复
  • 启示机械式响应的告警是技术债务的红旗,团队不愿自动化暗示对清偿债务缺乏信心

长期视角

"今天的每次告警都在分散人类改善明天系统的注意力"

  • 短期可用性下降换取长期稳定是战略性权衡
  • 季度向管理层汇报告警频率(每班次事件数),确保决策者了解团队负荷
  • 依赖人力维持高可用性是不可持续的,会导致倦怠和英雄主义依赖

结论

健康的监控告警管道应:

  • 简单易懂,主要关注症状而非原因
  • 向上层栈监控症状更容易,但子系统(如数据库)需直接监控饱和度
  • 邮件告警价值有限易成噪音,改用仪表盘监控次级问题
  • ✅ 支持快速诊断,告警指向症状或即将发生的真实问题
  • ✅ 目标实际可达,避免不可实现的SLO

第七章 自动化的演进

自动化的价值

价值维度具体说明
一致性机器比人类更一致地执行任务,减少错误和疏忽
平台化好的自动化成为可扩展、可复用的平台
快速修复降低平均修复时间(MTTR),提高开发速度
快速响应机器反应速度远超人类,适用于故障转移等场景
节省时间将操作者与操作解耦,节省团队整体时间

关键洞察:自动化的价值不仅在于"做什么",更在于**"明智地应用"**。

自动化的五个演进阶段

阶段1: 无自动化 → 人工操作(如手动数据库主备切换)

阶段2: 外部维护的特定系统自动化 → SRE个人脚本

阶段3: 外部维护的通用自动化 → 共享的通用脚本

阶段4: 内部维护的特定系统自动化 → 系统自带自动化脚本

阶段5: 无需自动化的自治系统 → 系统自动处理问题,无需人工干预

终极目标:自治系统(Autonomous Systems),而非仅仅是自动化系统。

三个关键案例研究

案例1:MySQL on Borg(自动化消除工作)

背景:2008年将MySQL迁移到Google的集群调度系统Borg,但Borg任务每周移动1-2次,而主库故障转移需要30-90分钟。

解决方案:开发"Decider"自动化故障转移守护进程

  • 故障转移时间:<30秒(95%的情况)
  • 结果:团队运维工作时间下降95%
  • 最终:团队成功"自动化掉了自己的工作"

关键转变:从"优化避免故障"转向"拥抱故障不可避免,优化快速恢复"


案例2:集群启动自动化(自动化的陷阱)

演进历程

  1. 初期:SSH脚本加速交付 → 技术债务累积
  2. Prodtest阶段:用Python单元测试框架检测配置错误
  3. 修复自动化:将测试与修复配对,实现幂等修复
  4. 专业化陷阱:为提速将自动化交给专门团队 → 质量下降
  5. 服务导向架构:各服务团队维护自己的Admin Server

关键教训

"最实用的工具通常由使用它们的人编写"

将自动化与运维责任分离会产生不良组织激励

  • 提速团队无动力减少技术债务
  • 不运行自动化的团队无动力构建可自动化系统
  • 产品经理总是优先新功能而非简化

案例3:Borg与仓库级计算机

核心思想:将集群管理从"静态主机分配"转变为"资源海洋"

  • 把机器集合视为可管理的资源池
  • 通过API调用而非人工操作管理集群
  • 实现自动修复:数千台机器每天自动诞生、死亡、维修,无需SRE干预

"通过将集群管理视为软件问题,我们将自动化转变为自治"

重要警示:自动化的风险

大规模故障案例:Diskerase事件

事故经过

  1. 自动化在擦除磁盘后失败
  2. 重启调试时,空集合被错误解释为"全部"
  3. 几分钟内,全球CDN的所有机器磁盘被擦除

后果

  • 用户连接终止能力丧失
  • 靠自有数据中心维持服务(用户几乎无感知)
  • 花费两天重装机器,数周审计和加固

改进措施:添加合理性检查、速率限制、幂等性设计


关键建议

建议说明
设计阶段就考虑自治自治性难以事后 retrofit 到大型系统
可靠性是根本特性自主、弹性的行为是实现可靠性的有效途径
标准软件工程实践解耦子系统、引入API、最小化副作用
保持人类操作能力高度自动化可能导致人类操作技能退化
定期演练防止"自动化失效时人类无法操作"的情况

自动化的最高境界不是"让机器执行人类指令",而是"设计不需要指令的系统" —— 从自动化(Automation)走向自治(Autonomy)。

第八章 发布工程 Release Engineering

一、发布工程师的职责是什么?

发布工程师的核心职责是构建和交付软件,具体包括:

  1. 定义发布流程:与软件开发工程师(SWE)和站点可靠性工程师(SRE)合作,定义从源代码存储、编译构建规则到测试、打包和部署的完整发布步骤。

  2. 工具开发与度量:开发工具来报告各类指标(如代码变更部署到生产环境所需的时间/发布速度、构建配置文件中的功能使用统计等)。

  3. 制定最佳实践:定义工具使用的最佳实践,确保项目使用一致且可重复的方法论进行发布,包括编译器标志、构建标识标签格式、构建过程中的必需步骤等。

  4. 协作与策略制定:与SRE合作开发变更金丝雀发布(canarying changes)、无中断推送新发布、以及问题功能回滚等策略。

  5. 确保可靠性与安全性:确保发布过程满足业务需求,实施多层安全和访问控制,管理谁可以在发布过程中执行特定操作。


二、发布工程师要完成哪些任务?依据什么方法论?

主要任务

任务类别具体内容
构建管理使用Blaze等构建工具定义构建目标、管理依赖关系、确保构建的可重复性
分支管理从主干(mainline)创建发布分支,管理cherry pick(挑选特定变更到发布分支)
测试集成配置持续测试系统,确保发布分支的单元测试通过,创建测试通过的审计追踪
打包发布使用MPM(Midas Package Manager)打包构建产物,应用标签管理版本
部署管理通过Rapid或Sisyphus等系统驱动部署,管理配置分发
配置管理与SRE协作,决定配置文件的存储和分发策略(主干存储、与二进制打包、配置包分离或外部存储)

核心方法论(四大原则)

  1. 自助服务模型(Self-Service Model)

    • 产品开发团队能够自主控制和运行自己的发布流程
    • 发布流程自动化到工程师只需在出现问题时介入的程度
  2. 高速度(High Velocity)

    • 频繁发布,减少版本间的变更量,使测试和故障排查更容易
    • 采用"绿版即推"(Push on Green)模式,自动部署通过所有测试的构建
  3. 封闭构建(Hermetic Builds)

    • 构建结果不受构建机器上安装的库和其他软件影响
    • 构建依赖已知版本的构建工具(如编译器)和依赖项
    • 构建过程自包含,不依赖构建环境外部的服务
    • 支持通过cherry pick重建旧版本
  4. 策略与流程的强制执行(Enforcement of Policies and Procedures)

    • 多层安全和访问控制管理发布操作权限
    • 几乎所有代码变更都需要代码审查
    • 自动生成包含所有变更的报告并归档

三、如何验证发布工程师的产出是合格的?

根据文本,合格的发布工程师产出可以通过以下方式验证:

1. 构建的可重复性(Reproducibility)

  • 两人在不同机器上使用相同源代码版本号构建同一产品,应获得完全相同的结果
  • 构建是封闭的(hermetic),不依赖构建机器的本地环境

2. 自动化与一致性

  • 发布流程高度自动化,仅需在出现问题时需要工程师介入
  • 使用一致且可重复的方法论发布项目
  • 工具默认行为正确且有充分文档,团队无需重复造轮子

3. 测试覆盖率与通过性

  • 持续测试系统每次代码提交都运行单元测试
  • 发布时重新运行单元测试,创建测试通过的审计追踪
  • 确保测试在实际发布的代码上下文中通过(考虑cherry pick情况)

4. 发布速度与业务指标

  • 度量发布速度(release velocity):代码变更部署到生产环境所需时间
  • 统计构建配置文件中的功能使用情况
  • 频繁发布且版本间变更少,使测试和故障排查更容易

5. 安全与合规性

  • 所有变更都有代码审查记录
  • 自动生成并归档包含所有变更的报告
  • 多层访问控制确保只有授权人员能执行关键操作

6. 部署可靠性

  • 支持金丝雀发布(canary deployment),在小规模生产环境验证
  • 能够无中断地推送新发布
  • 具备快速回滚问题功能的能力

7. 配置管理的正确性

  • 配置文件与二进制文件的版本关系清晰
  • 支持独立更新配置而无需重新构建二进制文件
  • 使用标签系统确保可以精确引用特定版本的包

总结:发布工程师的合格产出体现在可重复的构建过程、自动化的发布流水线、全面的测试覆盖、严格的访问控制、快速的发布速度以及灵活的部署策略等方面,最终目标是使发布过程像"按一下按钮"那样简单无痛。

第九章 简洁性 Simplicity

软件简洁性是可靠性的前提。 每一行新代码都是潜在的负债,而非资产。

1. 稳定性 vs 敏捷性

  • SRE的工作是在稳定性和敏捷性之间保持平衡
  • 可靠性实践实际上能提升开发敏捷性:快速、可靠的发布让问题更容易被发现和修复

2. "无聊"的美德

  • 软件应该可预测、无趣,而非充满"惊喜"
  • 本质复杂性:问题本身固有的,无法消除
  • 偶然复杂性:可以通过工程努力消除的,SRE应持续推动消除这类复杂性

3. 代码删除哲学

  • 反对保留"可能以后用得上"的代码(注释掉的代码、永远关闭的功能开关)
  • 源代码控制系统已经能恢复历史代码,不需要保留垃圾代码
  • Knight Capital的案例警示:废弃代码是"定时炸弹"

4. "负代码行数"指标

  • 删除无用代码是最令人满足的编程工作之一
  • 小项目更容易理解、测试,缺陷更少

5. 最小化API设计

  • 引用圣埃克苏佩里的话:"完美不是无可添加,而是无可删减"
  • API方法越少、参数越少,越容易理解和优化

6. 模块化

  • 松耦合:允许独立修改、独立部署
  • API版本控制:让升级变得安全、可控
  • 避免"工具箱/杂项"式的二进制文件,每个组件应有清晰、明确的职责
  • 数据格式也应模块化(如Google Protocol Buffers的前后向兼容设计)

7. 发布简洁性

  • 小批量发布优于大批量发布
  • 单次变更更容易衡量影响
  • 类比机器学习中的梯度下降:小步迭代,快速验证

"不"也是一种创新——拒绝不必要的功能,保持环境整洁,让真正的工程创新得以聚焦和推进。

第十三章 应急响应

一、应急响应的基本原则

  • 不要恐慌 — 你是受过训练的专业人员
  • 寻求帮助 — 必要时可以呼叫整个公司支援
  • 遵循流程 — 熟悉并执行公司的应急响应流程

二、三个真实案例研究

1. 测试引发的紧急事件

  • 背景:为排查隐藏依赖,SRE 团队封锁了测试数据库的访问
  • 后果:大量依赖服务瘫痪,内外部用户无法访问关键系统
  • 响应:立即中止测试,1小时内恢复权限,并行修复数据库应用层库
  • 教训
    • 对系统交互理解不足
    • 未遵循新建立的应急响应流程
    • 回滚程序未在测试环境验证

2. 变更引发的紧急事件

  • 背景:周五全球推送防滥用配置变更,触发崩溃循环bug
  • 后果:整个服务集群几乎同时崩溃,内部应用也无法访问
  • 响应:5分钟内回滚变更,10分钟内宣布事故,1小时内大部分服务恢复
  • 教训
    • 灰度测试(canary)不够彻底,未覆盖特定配置组合
    • 监控告警过于频繁,淹没有效信息
    • 依赖自身工具存在风险
    • 运气因素:推送工程师碰巧看到投诉并快速回滚

3. 流程引发的紧急事件

  • 背景:服务器退役自动化测试时,bug 导致全球所有小型服务器被误加入磁盘擦除队列
  • 后果:全球小型服务器安装点被批量擦除,触发大规模告警
  • 响应:1小时内转移流量,3小时重建首个站点,3天内恢复绝大部分容量
  • 教训
    • 自动化缺乏健全性检查("零值意味着全部")
    • 重装基础设施性能差(TFTP低优先级、BIOS处理失败差、并发限制)
    • 团队应急响应流程已成熟,协作出色

关键经验与建议

方面核心建议
心态所有问题都有解决方案;扩大求助范围,快速行动
事后学习建立事故历史档案,彻底、诚实地撰写事后分析,追究改进行动
预防性思考提出"如果..."的大胆假设:断电、水灾、数据中心瘫痪、服务器被入侵等
主动测试与其让故障在凌晨2点意外发生,不如在白天主动测试

结论

Google 的应急响应方法论可应用于任何规模的组织:

  • 保持冷静,协作应对
  • 从历史事故中学习
  • 构建更具韧性的系统
  • 持续进行主动测试

"Things break; that's life." — 故障是常态,响应能力决定组织的长期健康。