读书笔记:SRE Google 运维解密

前言 xxxi

序言 xxxv

站点可靠性工程师(SRE, Site Reliability Engineering)。

使用示例代码

补充材料可以到http://g.co/SREBook下载。

第Ⅰ部分 概览

第1 章 介绍 2

系统管理员模式 2

研发部门最关注的是如何能够更快速地构建 和发布新功能。运维部门更关注的是如何能在他们值班期间避免发生 故障。由于绝大部分生产故障都是由于部署某项变更导致的—不管是 部署新版本,还是修改配置,甚至有时只是因为改变了用户的某些行 为造成了负载流量的配比变化而导致故障。这两个部门的目标从本质 上来说是互相矛盾的。

运维团队常常宣称,任何变更 上线前必须经过由运维团队制定的流程,这有助于避免事故的发生。

而开发团队吃过苦头 之后也很快找到了自己的应对办法:开发团队宣称他们不再进行大规 模的程序更新,而是逐渐转为功能开关调整、增量更新,以及补丁化。采用这些名词的唯一目的,就是为了绕过运维部门设立的各种流 程,从而能更快地上线新功能。

Google 的解决之道:SRE 4

SRE 这种模型是Google尝试着从根本上避免产生这种矛盾的结 果。SRE团队通过雇佣软件工程师,创造软件系统来维护系统运行以替 代传统模型中的人工操作。

SRE团队成员 具有如下特点:
(a)对重复性、手工性的操作有天然的排斥感。
(b)有足够的技术能力快速开发出软件系统以替代手工操作。

SRE 方法论 6

一般来说, SRE团队要承担以下几类职责:可用性改进,延迟优化,性能优化,效 率优化,变更管理,监控,紧急事务处理以及容量规划与管理。

确保长期关注研发工作 6

在保障服务SLO 的前提下最大化迭代速度 7

如果100% 不是一个正确的可靠性目标,那么多少才是呢?这其实 并不是一个技术问题,而是一个产品问题。要回答这个问题,必须考 虑以下几个方面:

  • 基于用户的使用习惯,服务可靠性要达到什么程度用户才会满 意?
  • 如果这项服务的可靠程度不够,用户是否有其他的替代选择?
  • 服务的可靠程度是否会影响用户对这项服务的使用模式?

公司的商业部门或者产品部门必须建立起一个合理的可靠性目 标。一旦建立,“错误预算”就是“1-可靠性目标”。如果一个服务 的可靠性目标是99.99%,那么错误预算就是 0.01%。这意味着产品研 发部门和SRE部门可以在这个范围内将这个预算用于新功能上线或者产 品的创新等任何事情。

监控系统 8

但是这样的报警策略并不是非常有效:一个需 要人工阅读邮件和分析警报来决定目前是否需要采取某种行动的系统 从本质上就是错误的。
一个监控系统应该只有三类输出。

  • 紧急警报(alert)意味着收到警报的用户需要立即执行某种操作
  • 工单(ticket)意味着接受工单的用户应该执行某种操作,
  • 日志(logging)但是日志信息依然被收集起来以 备调试和事后分析时使用。

应急事件处理 8

可靠性是MTTF(平均失败时间)和MTTR(平均恢复时间)的函数。
但是长久看来一个手持“运维宝 典”经过多次演习的on-call工程师才是正确之路。

变更管理 9

SRE的经验告诉我们,大概 70% 的生产事故由某种部署的变更而 触发。

  • 采用渐进式发布机制。
  • 迅速而准确地检测到问题的发生。
  • 当出现问题时,安全迅速地回退改动。

需求预测和容量规划 9
资源部署 10
效率与性能 10
小结 10

第2 章 Google 生产环境:SRE 视角 11

硬件 11
管理物理服务器的系统管理软件 13
管理物理服务器 13
存储 14
网络 15
其他系统软件 16
分布式锁服务 16
监控与警报系统 16

软件基础设施 17

通常来说,一个软件服务器从该服务的前端(frontend)接收RPC 请求,同时将另外一些RPC发往该服务器的后端(backend)。一般来 说,前端被称为客户端(client),后端被称为服务端(server)。

研发环境 17

莎士比亚搜索:一个示范服务 18

批处理部分可以用MapReduce框架完成,三个阶段的实现分别如下 所示。

  • Mapping 阶段:该程序遍历所有的莎士比亚的文字,将其分成 具体的单词。这项任务可以利用多实例并行加速。
  • Shuffle 阶段:该程序将上一阶段产生的所有单词和位置等进 行排序。
  • Reduce 阶段:将上一阶段产生的单词或位置等按单词合并, 产生一个新的单词或位置列表。

用户请求的处理过程 18

后端服务器将其回复给Shakespeare前端服务器,前端服务 器最终根据这个数据结构构建HTML回复给最终用户。

任务和数据的组织方式 19

第Ⅱ部分 指导思想

第3 章 拥抱风险 23

管理风险 23

可靠性进一步 提升的成本并不是线性增加的—可靠性的下一个改进可能比之前的改 进成本增加100倍。高昂的成本主要存在于以下两个维度。

  • 冗余物理服务器/计算资源的成本
  • 机会成本。这些工程师不能再从事为终端用户设计新功能和新产品的工作。

度量服务的风险 24

Google标准做法是通过一个客观的指标来体现一个待优化的系统 属性。
对于大多数服务而言,最直接的能够代表风险承受能力的指标就 是对于计划外停机时间的可接受水平。
公式3-1:基于时间的可用性
可用性=系统正常运行时间/(系统正常运行时间+停机时间)
举例来说,一个可用性目标为99.99%的 系统最多在一年中停机52.56分钟,就可以达到预计的可用性目标;详 情参见附录A。

公式3-2:合计可用性
可用性=成功请求数/总的请求数
例如,一个每天可用性目标为99.99%的系统,一天要接受2.5M个 请求。它每天出现少于250个错误即可达到预计的可用性目标。

服务的风险容忍度 25
辨别消费者服务的风险容忍度 26
基础设施服务的风险容忍度 28

使用错误预算的目的 30

下面列举一些典型的紧张局势。

  • 软件对故障的容忍度
  • 测试。而过于强调测试可能会失 去市场先机。
  • 发布频率。每一次发布都是有风险的。我们应该花多少时间在减少风险上?
  • 金丝雀测试(Canary)的持续时间和大小。我们要等多久,而 且测试范围有多大?

相反,我们的目标是定义一个双方都同意的客观指标,该指标可 以用来指导谈判的方向。一项决策越是基于数据做出的,常常就越 好。

错误预算的构建过程 31

我们的实际做法如下:

  • 产品管理层定义一个SLO,确定一项服务在每个季度预计的正 常运行时间。
  • 实际在线时间是通过一个中立的第三方来测算的:我们的监控 系统。
  • 这两个数字的差值就是这个季度中剩余的不可靠性预算。
  • 只要测算出的正常在线时间高于SLO,也就是说,只要仍然有 剩余的错误预算,就可以发布新的版本。

好处 32

第4 章 服务质量目标 34

服务质量指标(SLI)、服务质量目标 (SLO),以及服务质量协议(SLA)。

服务质量术语 34

指标 34

SLI是指服务质量指标(indicator)—该服务的某项服务质量的 一个具体量化指标。

目标 35

SLO是服务质量目标(Objective):服务的某个SLI的目标值,或 者目标范围。

协议 36

SLA是服务质量协议(Agreement):指服务与用户之间的 一个明确的,或者不明确的协议,描述了在达到或者没有达到SLO之后 的后果。

指标在实践中的应用 37
运维人员和最终用户各关心什么 37
指标的收集 37
汇总 38
指标的标准化 39

目标在实践中的应用 39

目标的定义 40

目标的选择 40

  • 不要仅以目前的状态为基础选择目标。但是仅仅按照当前系统的 标准制定目标,而不从全局出发,可能会导致团队被迫长期运维一个 过时的系统,没有时间去推动架构重构等任务。
  • 保持简单
  • 避免绝对值
  • SLO越少越好
  • 不要追求完美

控制手段 42
SLO 可以建立用户预期 42
协议在实践中的应用 43

第5 章 减少琐事 44

琐事的定义 44

每件琐 事都满足下列一个或多个属性:

  • 手动性
  • 重复性的
  • 可以被自动化的
  • 战术性的
  • 没有持久价值
  • 与服务同步线性增长

为什么琐事越少越好 45

SRE的一个公开目标是保持每个SRE的工作时间中运维工作(即琐 事)的比例低于50%。SRE至少花50%的时间在工程项目上,以减少未来 的琐事或增加服务功能。

什么算作工程工作 46

工程工作(Engineering)是一种新颖的、本质上需要主观判断的 工作。它是符合长期战略的,会对你的服务进行长久性的改善的工 作。
典型的SRE活动分为如下几类。

  • 软件工程。编写或修改代码
  • 系统工程。的架构、设计和生产环境方面的 咨询工作。
  • 琐事
  • 流程负担。与运维服务不直接相关的行政工作。例如招聘

琐事繁多是不是一定不好 47

在许多琐事有害的原因中,有如下因素需要考虑:

  • 职业停滞
  • 士气低落。过多的琐事会导致过度劳累、厌倦和不满。

做琐事会对SRE组织的整体发展造成损害, 原因如下:

  • 造成误解
  • 进展缓慢
  • 开创先例。如果SRE过于愿意承担琐事,研发同事就更倾向于加入更多的琐事
  • 促进摩擦产生
  • 违反承诺。及转入SRE的老员工会 有被欺骗的感觉
    小结 48

第6 章 分布式系统的监控 49

术语定义 49

  • 监控(monitoring)。收集、处理、汇总,并且显示关于某个系统的实时量化数据
  • 监控台页面(dashboard)。提供某个服务核心指标一览服务的应用程序(一般是基于Web 的)。
  • 警报(alert)。 目标对象是某个人发向某个系统地址的一个通知。
  • 根源问题(root cause)。 指系统(软件或流程)中的某种缺陷。

为什么要监控 50

对监控系统设置合理预期 51

一般来说,Google趋向于使用简单和快速的监控系统配合高效的 工具进行事后分析。我们会避免任何“魔法”系统—例如试图自动学 习阈值或者自动检测故障原因的系统。
监控系统信噪比应该很高,发出紧急警报的组件需要非 常简单而且可靠。产生警报的监控系统规则应该非常容易理解,同时 代表一个清晰的故障场景。

现象与原因 52

监控系统应该解决两个问题:什么东西出故障了,以及为什么出 故障。
“什么东西出故障了”即为现象(symptom):“为什么”则代表 了原因(可能只是中间原因,并不是根源问题)。
“现象”和“原因”的区分是构建信噪比高的监控系统时最重要 的概念。

黑盒监控与白盒监控 53

4 个黄金指标 53

如果我们只能监控用户可见系统的4个指标,那么就 应该监控这4个。

  • 延迟。 服务处理某个请求所需要的时间。
  • 流量。 使用系统中的某个高层次的指标针对系统负载需求所进行的度 量。
  • 错误。 请求失败的速率,要么是显式失败(例如HTTP 500),要么是隐 式失败(例如HTTP 200 回复中包含了错误内容)
  • 饱和度。 服务容量有多“满”。通常是系统中目前最为受限的某种资源的 某个具体指标的度量。(在内存受限的系统中,即为内存;在I/O受限 的系统中,即为I/O)。

关于长尾问题 54

区分平均值的“慢”和长尾值的“慢”的一个最简单办法是将请 求按延迟分组计数(可以用来制作直方图):延迟为0~10ms之间的请 求数量有多少,30~100ms之间,100~300ms之间等。

度量指标时采用合适的精度 55
简化,直到不能再简化 55
将上述理念整合起来 56
监控系统的长期维护 57
Bigtable SRE :警报过多的案例 57
Gmail :可预知的、可脚本化的人工干预 58
长跑 59
小结 59

第7 章 Google 的自动化系统的演进 60

自动化的价值 60

一致性 60

平台性 61

一个平台同时也将错误集中化了。

修复速度更快 61

可以降低一些常见故障的平均修复时间(MTTR)。

行动速度更快 62
节省时间 62
自动化对Google SRE 的价值 62
自动化的应用案例 63
Google SRE 的自动化使用案例 63
自动化分类的层次结构 64
让自己脱离工作:自动化所有的东西 66

舒缓疼痛:将自动化应用到集群上线中 67

使用Prodtest 检测不一致情况 68
幂等地解决不一致情况 69

专业化倾向 71

最可用的工具通常是由那些每天使用它们的人写成的。

以服务为导向的集群上线流程 72

集群上线自动化进化遵循这样一个路径:
1.操作人员触发手动操作(无自动化)。
2.操作人员编写,系统特定的自动化。
3.外部维护的通用自动化。
4.内部维护,系统特定的自动化。
5.不需要人为干预的自治系统。

Borg :仓库规模计算机的诞生 73
可靠性是最基本的功能 74
建议 75

第8 章 发布工程 76

发布工程(Release Engineering)简单来说,这个学科专注于构建和交付软件。发布工程师通常对源代码管理、编译器、构建配置语 言、自动化构建工具、包管理器和安装器等非常了解(甚至是这方面 的专家)。

发布工程师的角色 76

发布工程哲学 77

自服务模型 77

发布工程师 开发工具,制定最佳实践,以便让产品研发团队可以自己掌控和执行 自己的发布流程。

追求速度 77

还有的团队采用一种“测试通过 即发布”(Push On Green)的发布模型

密闭性 77

构建工具必须确保一致性和可重复性。构建 过程使用指定版本的构建工具(编译器),同时使用指定版本的依赖 库(第三方类库)。编译过程是自包含的,不依赖于编译环境之外的 其他服务。

强调策略和流程 78

  • 批准源代码改动—通过源代码仓库中的配置文件决定。
  • 批准初始的集成请求
  • 实际部署某个发布版本。

持续构建与部署 78
构建 78
分支 79
测试 79
打包 79
Rapid 系统 80
部署 81
配置管理 81
小结 82
不仅仅只对Google 有用 83
一开始就进行发布工程 83

第9 章 简单化 85

软件系统本质上是动态的和不稳定的。

系统的稳定性与灵活性 85
乏味是一种美德 86

我绝对不放弃我的代码 86

源代码控制 系统中的更改反转很容易,数百行的注释代码则会造成干扰和混乱 (尤其是当源文件继续演进时);那些由于功能开关没有启用而没有 被执行的代码,就像一个定时炸弹一样等待爆炸。

“负代码行”作为一个指标 87

最小 API 87

法国诗人 Antoine de Saint Exupery 曾写道,“不是在不能添 加更多的时候,而是没有什么可以去掉的时候,才能达到完美。”这个原则同样适用于软件的设计和构建。
书写一个明确的、最小的API 是管理软件系统管理简单性必要的 部分。我们向API消费者提供的方法和参数越少,这些API就越容易理 解

模块化 87
发布的简单化 88
小结 88

第Ⅲ部分 具体实践

监控

在第10章将讨论有关警报系统的设计哲学和工具。

应急事件处理

在第11章中,将详细解释我们是如 何平衡on-call轮值与其他工作的。
在第12章中,我们提供了一套结构化方案来解决问题的第一步: 找到问题所在。
在第13章和第14章中,我们讨论了如何通过 合理的流程有效地减小事故的影响范围,以缓解整个部门由生产事故 带来的压力。

事后总结和问题根源分析

第15章,描述了如何建立起“无指责”、“对事不对人”的团队 文化
第16章,在这个基础上,我们简要描述了一个内部工具,事故跟 踪系统。

测试

保证软件在发布到生产环境中时 不会出现某些类型的问题。在第17章中详细描述了相关的最佳实践。

容量规划

在第18章中,我们给出了一个具体的工具开发实践案例。SRE 利 用Google 内部工具Auxon,自动化进行服务容量规划。
在第19章中,我们讨论了用户请求是如何发送到数 据中心的。在第20章和第21章中,我们详细描述了数据中心中的负载 均衡体系是保障服务可靠度的关键。 最后,在第22章中,我们讨论了如何从系统设计层面与战术层面 应对“连锁故障”。

软件研发

在第23章中,我们解释了Google许多系统的核心组件—“分布式 共识”系统(Paxos的新说法),在第 24章中,我们描述了SRE是如何设计和部署一个跨数据中心的定时任务 系统的。第25章描述了批量数据处理系统的几种形态:从定时运行的 MapReduce程序,到实时数据处理系统。
在第26章中,我们详细描述了数据一致性的重要性

产品设计

在第27章中,我们描述了处于整个可靠度金字塔模型顶端 的产品设计理念。

第10 章 基于时间序列数据进行有效报警 93

Borgmon 的起源 94
应用软件的监控埋点 95
监控指标的收集 96

时间序列数据的存储 97

些数据都是以类似 (timestamp,value)的格式存储在一个按时间排序的链表里,该链表称为Ti m eseries。

标签与向量 98
Borg 规则计算 99
报警 104
监控系统的分片机制 105
黑盒监控 106
配置文件的维护 106
十年之后 108

第11 章 on-call 轮值 109

介绍 109
on-call 工程师的一天 110

on-call 工作平衡 111

数量上保持平衡 111

多地团队相比之下有以下两点优势:

  • 长时间执行夜间任务对人的健康不利(参见文献[Dur05])。 多地团队可以利用“日出而作,日落而息”(Follow the sun)的轮 值制度使整个团队避免夜间值班。

质量上保持平衡 111
补贴措施 112
安全感 112
避免运维压力过大 114
运维压力过大 114
奸诈的敌人—运维压力不够 115
小结 115

第12 章 有效的故障排查手段 116

理论 117

针对某系统的 一些观察结果和对该系统运行机制的理论认知,我们不断提出一个造成系统问题的假设,进而针 对这些假设进行测试和排除。

[!NOTE]
常见的陷阱
造成低效的故障排查过程的原因通常集中在定位(triage)、检查和诊断环节上,主要由于对 系统不够了解而导致。下面列举了一系列常见的陷阱,读者应该小心避免:

  • 关注了错误的系统现象,或者错误地理解了系统现象的含义。这样会在错误的方向上浪费 时间。
  • 将问题过早地归结为极为不可能的因素,或者念念不忘之前曾经发生过的系统问题, 认为一旦发生过一次,就有可能再次发生。
  • 试图解决与当前系统问题相关的一些问题,却没有认识到这些其实只是巧合,或者这些问 题其实是由于当前系统的问题造成的。

最后,我们要记住,相关性(correlation)不等于因果关系(causation)。一些同时出现的 现象,例如集群中的网络丢包现象和硬盘损坏现象可能是由同一个原因造成的,比如说供电故 障。但是网络丢包现象并不是造成硬盘损坏现象的原因,

实践 119

故障报告 119

有效的故障报告应该写清预期是什么,实际的结果是什么,以及如何重现。

定位 119
检查 120

诊断 122

简化和缩略

如果系统有配套的测试用例,那么调试起来就会 很容易。甚
问题分解(Divide & Conquer)也是一个非常有用的通用解决方案。最好的办法通常是从系统的一端开始,逐个检查每一个组 件,直到系统最底层。这样的策略非常适用于数据处理流水线。在大型系统中,逐个检查可能太 慢了,可以采用对分法(bisection)将系统分为两部分,确认问题所在再重复进行。

“什么”“哪里”和“为什么”

那么找出系统目前正在执行“什么”,然后通过询问该系统“为什么”正在做这些操作, 以及系统的资源都被用在了“哪里”可以帮助你了解系统为什么出错。

最后一个修改

计算机系统有惯性存在:我们发现,一个正常工作的计算机系统会维持工作,直到某种外力 因素出现
通过将系统的环 境改变与系统性能和行为进行对比,可能比较有用。例如,在服务的监控页面上,你可以将系统 的错误率图表和新版本的部署起始时间和结束时间标记在一起,

有针对性地进行诊断

虽然前面论述的通用性工具在很多问题上都很有用,但是针对具体系统开发的诊断工具和诊 断系统会更有用。

测试和修复 124

在设计测试时,有一些考量必须时刻记住。

  • 一个理想的测试应该具有互斥性,通过执行这个测试,可以将一组假设推翻
  • 先测试最可能的情况:按照可能发生的顺序执行测试,先测试网络连通性,再检查是否是最近的配置文件改变导致用户无法访问某机器可能更合 理。
  • 某项测试可能产生有误导性的结果。
  • 执行测试可能会带来副作用。
  • 某些测试无法得出准确的结论,只是建议性的。

将你的想法明确地记录下来,包括你执行了哪些测试,以及结果是什么。良好的文档可以让你记住曾经发生过什么,可避免重复执行。

神奇的负面结果 125

负面结果不应该被忽略,或者被轻视。 意识到自己的错误通常意义更大:一个明确的负面结 果可以给某些最难的设计问题画上句号。一个团队经常同时有两个看起来可行的设计方向可供选 择
一项试验中出现的负面结果是确凿的。 这些结果确切地告诉了我们有关生产环境中的信息、 设计理念对错或者现有系统的性能极限。
工具和方法可能超越目前的试验,为未来的工作提供帮助。 将 这些测试写成脚本有助于保证在下一个项目中你不会忘记和错过好的优化点。
公布负面结果有助于提升整个行业的数据驱动风气。

治愈 126

下一步,我们想要证明这 就是问题根源。在生产环境中试图通过重现一个原因而明确地证明它就是问题的原因是很困难 的。因为如下几个原因,我们经常只能发现可能的原因。

  • 系统复杂度。很有可能有多个因素共同作用导致系统问题。它们必须处于一个特定状态下问题才会发生。
  • 在生产环境中重现某个问题也许是不可能的。要么因为将系统置于某种问题状态过于复 杂,或者是系统过于重要,不能再出问题。

你是如何定位问题的, 和你是如何修复问题的,如何防止再次发生等写下来。这就是事后总结。

案例分析 127
使故障排查更简单 130
小结 130

第13 章 紧急事件响应 131

当系统出现问题时怎么办 131
测试导致的紧急事故 132
细节 132
响应 132
事后总结 132
变更部署带来的紧急事故 133
细节 133
事故响应 134
事后总结 134
流程导致的严重事故 135
细节 135
灾难响应 136
事后总结 136
所有的问题都有解决方案 137

向过去学习,而不是重复它 138

为事故保留记录 138

历史就是学习 其他人曾经犯的错误。提出关键的问题。时刻寻找如何能在战术及战略上避 免这项事故的发生。

提出那些大的,甚至不可能的问题:假如…… 138

我们应该提出一些大的、没有 确切答案的问题。假如整栋大楼的电源坏了怎么办?

鼓励主动测试 138
小结 138

第14 章 紧急事故管理 140

如果事先没有针对可能发生的紧急事故进行过演习,那么当事故 发生时,一切管理理念都起不了作用。

无流程管理的紧急事故 140
对这次无流程管理的事故的剖析 141
过于关注技术问题 141
沟通不畅 141
不请自来 142

紧急事故的流程管理要素 142

嵌套式职责分离 142

在事故处理中,让每个人清楚自己的职责是非常重要的。
以下是系统中可以分配给某个人的角色。

  • 事故总控(incident command)。他们负责组建事故处 理团队,按需求和优先级将一些任务分配给团队成员。
  • 事务处理团队(operational work)。负 责指挥团队具体执行合适的事务来解决问题。
  • 发言人(communication)。该人是本次事故处理团队的公众发言人。他的职责包括向事故处 理团队和所有关心的人发送周期性通知(通常以电子邮件形式)
  • 规划负责人(planning)。负责处理一些持续性 工作,例如填写Bug报告记录系统,给事务处理团队订晚餐,安排职责 交接记录。

控制中心 143

可以设立一个“作战室”(war room),将处 理问题的全部成员挪到该地办公。

实时事故状态文档 143

事故总控负责人最重要的职责就是要维护一个实时事故文档。

明确公开的职责交接 143

超出工作时间以后,事故总控负责人的职责能够明确、公开地进 行交接是很重要的。

一次流程管理良好的事故 144

什么时候对外宣布事故 144

如果下面任何一条满足条件,这次事故应该被及时宣布。

  • 是否需要引入第二个团队来帮助处理问题?
  • 这次事故是否正在影响最终用户?
  • 在集中分析一小时后,这个问题是否依然没有得到解决?

如果平时不经常使用,事故流程管理的可靠性萎缩得很快。幸运的是,事故流程管理框架常常也适用于其他的跨时区、或 者跨团队的常规运维变更实施。

小结 145
第15 章 事后总结:从失败中学习 146
Google 的事后总结哲学 146
协作和知识共享 148
建立事后总结文化 149
小结以及不断优化 151

第16 章 跟踪故障 152

提高可靠性的唯一可靠的方法论是建立一个基线(baseline), 同时不断跟踪改变。

Escalator 152

Outalator 153

聚合 154

加标签 155

是提供了一种通用的标签机制,以允许对报警增加 元数据信息。标签基本上没有格式要求,都是独立的“单词”。
标签也可以被解析成一个链接(比如“bug:76543”将被解析成 Bug跟踪系统的一个链接)。

分析 155
未预料到的好处 156

第17 章 测试可靠性 157

[!NOTE]
测试和平均修复时间的关系
系统通过某项测试或者一系列测试并不一定能证明系统是稳定 的,但是失败的测试通常证明了系统不可靠。

软件测试的类型 158

系统测试

冒烟测试(smoke test)
工程师在冒烟测试中可检测非常简单但是非常重要的系统行为。 如果该测试不通过,那么其他更昂贵的测试可以不用运行了。

回归测试(regression test)
另外一种系统测试可保证之前的Bug不会重现。

传统测试 159
生产测试 160

创造一个构建和测试环境 163

当构建系统通知搞坏代码的工 程师时,他们应该放下手中的一切其他任务,优先处理该问题。这样 做的原因在于:

  • 如果问题引入系统之后,又有新的变动,修复会更难。
  • 不工作的代码会对团队造成影响,因为它们必须手动绕过这些 问题。
  • 定时地每晚构建和每周构建将失去意义。
  • 团队响应紧急发布的能力将会受到严重影响,甚者非常复杂和 困难(例如,发现代码中以及依赖中的安全漏洞等)。

大规模测试 165

测试大规模使用的工具 166
针对灾难的测试 167
对速度的渴求 168
发布到生产环境 170
允许测试失败 170

集成 172

使用现成的语法(如YAML)和一个经过大 量测试的分析器(例如Python的safe_load)可以将维护配置文件的成 本降低。

生产环境探针 173
小结 175

第18 章 SRE 部门中的软件工程实践 176

为什么软件工程项目对SRE 很重要 176
Auxon 案例分析:项目背景和要解决的问题 177
传统的容量规划方法 177
解决方案:基于意图的容量规划 179

基于意图的容量规划 180

“意图”是服务负责人对如何运维该服务的一个理性表达。从具 体的容量需求到背后理性原因的表达通常需要跳过几个抽象级别。举 例如下:
1.我需要50个CPU的资源,必须在集群X、Y、Z中,为服务Foo使 用。
这是一个具体的资源请求,但是,为什么我们需要这么多资源, 同时一定要在这三个集群中?
2.我需要50个CPU的资源,在地理区域YYYY中的任意三个集群 中,为服务Foo使用。
这项请求增加了更多的选择自由度,也更容易被满足,但是仍然 没有解释这项请求背后的原因,为什么我们需要这么多资源,以及为 什么需要三个集群?
3.我想要满足Foo在每个地理区域的需求增长,同时保障N+2冗余 度。
现在有了更多的选择自由度,同时我们可以更好地理解如果Foo没 有获得相应的资源,究竟会造成什么后果。
4.我们想要将Foo以99.999%的可靠度运行。
这是相对更抽象的一个需求,当容量得不到满足时的后果也更清 楚了:可靠性会下降。而且我们从中获得了更多的选择自由度:也许 以N+2运行并不是足够的,或者并不是最优化的情况,其他的某种部署 计划是更合适的。

表达产品意图的先导条件 181
Auxon 简介 182
需求和实现:成功和不足 183
提升了解程度,推进采用率 185
团队内部组成 187
在SRE 团队中培养软件工程风气 187
在SRE 团队中建立起软件工程氛围:招聘与开发时间 188
做到这一点 189
小结 190
第19 章 前端服务器的负载均衡 191
有时候硬件并不能解决问题 191
使用DNS 进行负载均衡 192
负载均衡:虚拟IP 194

第20 章 数据中心内部的负载均衡系统 197

理想情况 198

识别异常任务:流速控制和跛脚鸭任务 199

异常任务的简单应对办法:流速控制 199

一个可靠的识别异常任务的方法:跛脚鸭状态 200

从一个客户端的视角来看,某个后端任务可能处于下列任一种状态中:

  • 健康。
  • 拒绝连接。
  • 跛脚鸭状态。 后端任务正在监听端口,并且可以服务请求,但是已经明确要求客户端停止发送请求。

当某个请求进入跛脚鸭状态时,它会将这个状态广播给所有已经连接的客户端。
允许任务处于这种半正常的跛脚鸭状态的好处就是让无缝停止任务变得更容易,

利用划分子集限制连接池大小 201
选择合适的子集 201
子集选择算法一:随机选择 202
子集选择算法二:确定性算法 204
负载均衡策略 206
简单轮询算法 206
最闲轮询策略 209
加权轮询策略 210

第21 章 应对过载 212

QPS 陷阱 213
给每个用户设置限制 213
客户端侧的节流机制 214
重要性 216
资源利用率信号 217

处理过载错误 217

决定何时重试 218

们针对大量后端任务过载的情况有几个方法来避免进行 重试。
第一,我们增加了每次请求重试次数限制,限制重试3次。
第二,我们实现了一个每客户端的重试限制。每个客户端都跟踪 重试与请求的比例。一个请求在这个比例低于10%的时候才会重试。
第三个方法是客户端在请求元数据中加入一个重试计数。直到计数器 为2 时,请求重试限制会导致不再重试该请求。

连接造成的负载 220
小结 221

第22 章 处理连锁故障 223

连锁故障是由于正反馈循环(positive feedback)导致的不断扩大规模的故障。连锁故 障可能由于整个系统的一小部分出现故障而引发,进而导致系统其他部分也出现故障。例如,某 个服务的一个实例由于过载出现故障,导致其他实例负载升高,从而导致这些实例像多米诺骨牌 一样一个一个全部出现故障。

连锁故障产生的原因和如何从设计上避免 224

服务器过载 224
资源耗尽 225

服务不可用 228

某几个后端任务产生 了错误,会导致负载均衡器不再向它们发送请求,进而使得其余软件服务器的负载上升,从而再 次触发滚雪球效应。

防止软件服务器过载 228

当发送自动重试时,需要将如下部分考虑在内:

  • 一定要使用随机化的、指数型递增的重试周期。可参见文献[Bro15]中提到的文章 Exponential Backoff and Jitter(http://www.awsarchitectureblog.com/2015/03/backoff.html)。如果重试不是随机 分布在重试窗口里的,那么系统出现的一个小故障(某个网络问题)就可能导致重试请求同时出 现,这些请求可能会逐渐放大
  • 限制每个请求的重试次数。不要将请求无限重试。

队列管理 229
流量抛弃和优雅降级 230
重试 231
请求延迟和截止时间 234
慢启动和冷缓存 236
保持调用栈永远向下 238
连锁故障的触发条件 238
进程崩溃 239
进程更新 239
新的发布 239
自然增长 239
计划中或计划外的不可用 239
连锁故障的测试 240
测试直到出现故障,还要继续测试 240
测试最常用的客户端 241
测试非关键性后端 242
解决连锁故障的立即步骤 242
增加资源 242
停止健康检查导致的任务死亡 242
重启软件服务器 242
丢弃流量 243
进入降级模式 243
消除批处理负载 244
消除有害的流量 244
小结 244

第23 章 管理关键状态:利用分布式共识来提高可靠性 246

CAP 理论
CAP理论论述了一个分布式系统不可 能同时满足以下三个要求:

  • 每个节点上所见数据是一致的。
  • 每个节点都可以访问数据。
  • 可以承受网络分区问题。

该逻辑非常符合直觉:如果两个节点无法通信(因为网络出现了 分区问题),那么整个系统要么在一个或多个节点上无法处理数据访 问请求,要么可以照常处理请求,但是无法保障每个节点的数据具有 一致性。

使用共识系统的动力:分布式系统协调失败 248

案例1 :脑裂问题 249

每组文件服务器有一个领头者和一个跟随者,两组服务通过心跳 互相监控。如果某个文件服务器无法联系到另外一个服务器,它会发 送一个 STONITH(当头一枪)命令来强制关闭另外一个服务器,同时 成为文件的主服务者。这种机制是业界减少脑裂(split-brain)场景 发生的常规做法

案例2 :需要人工干预的灾备切换 249

某个外部系统检 查主实例的健康度,如果主实例出现问题,将副实例提升为主实例。 如果主实例无法确定副实例的健康度,那么它就会将自己标记为不可 用,将问题升级给人工处理,以便避免案例1中的脑裂场景发生。

案例3 :有问题的小组成员算法 249

分布式共识是如何工作的 250

当维护分布式软件系统时,我们关 注的是异步式分布式共识(asynchronous distributed consensus) 在消息传递可能无限延迟的环境下的实现。

拜占庭式问题指的是当某个进程由于程序Bug或者恶意行为发送不正确 的消息的问题,这种问题相对来说处理成本更高,同时也更少见。

Paxos 概要:协议示例 251

Paxos 是基于提案(proposal)序列运行的,这些提案可能会被 “大多数(majority)”进程所接受,也可能会被拒绝。

在协议的第一阶段,提案者(proposer)发送一个序列号给数个 接收者(acceptor)。每个接收者仅仅在没有接受过带有更高序列号 的提案情况下接受这个提案。提案者必须使用一个唯一的序列号(每个提案者从不相交的集 合中提取序列号,或者将自身的主机名加入到序列号中等)。

如果提案者从“大多数”接收者那里接收到了“同意”回复,它 便可以通过发送一个带有值的提交信息(commit message)来尝试提 交这个提案。

分布式共识的系统架构模式 251

可靠的复制状态机 252

一个复制状态机(replicated state machine,RSM)是一个能在 多个进程中用同样顺序执行同样的一组操作的系统。

可靠的复制数据存储和配置存储 252

使用领头人选举机制实现高可用的处理系统 253

在这种类型的组件里,不像复制数据存储那样,共识算法并不处 于系统的关键路径中,所以共识算法的吞吐量不是系统的主要问题。

分布式协调和锁服务 253

屏障(barrier)在分布式计算中是一种原语,可以用来阻挡一组 进程继续工作
屏障也可以用一个RSM系统来实现。
锁(lock)是另外一个很有用的协调性原语,在实践中,使用可续租约(renewable Lease)而不是无限时间锁 是很有必要的,避免某个进程崩溃而导致锁无限期被持有。

可靠的分布式队列和消息传递 254
分布式共识系统的性能问题 255
复合式Paxos :消息流过程详解 257
应对大量的读操作 258
法定租约 259
分布式共识系统的性能与网络延迟 259
快速Paxos 协议:性能优化 260
稳定的领头人机制 261
批处理 262
磁盘访问 262
分布式共识系统的部署 263
副本的数量 263
副本的位置 265
容量规划和负载均衡 266
对分布式共识系统的监控 270
小结 272

第24 章 分布式周期性任务系统 273

Cron 273

介绍 273

Cron系统在设计上允许系统管理员和普通系统用户指定在某时某 刻运行某个指令。Cron可以执行很多种类型的任务

可靠性 274
Cron 任务和幂等性 274
大规模Cron 系统 275
对基础设施的扩展 275
对需求的扩展 276
Google Cron 系统的构建过程 277
跟踪Cron 任务的状态 277
Paxos 协议的使用 277
领头人角色和追随者角色 278
保存状态 281
运维大型Cron 系统 282
小结 283

第25 章 数据处理流水线 284

流水线设计模式的起源 284
简单流水线设计模式与大数据 284

周期性流水线模式的挑战 285

周期性的数据流水线非常实用,Google也经常使用,为此还编写 了一系列程序框架,例如MapReduce和Flume等。

工作分发不均造成的问题 285

处理大数据的一个关键思想是利用“令人羞愧的并发性” (embarrassingly parallel)算法将巨大的工 作集切割为一个个可以装载在单独的物理机器上的小块。由于单个客户已经是系统 的最小分块单元,整个数据流水线的运行时间就至少等于处理最大的 客户的工作分块所需的时间。

分布式环境中周期性数据流水线的缺点 286
监控周期性流水线的问题 287
惊群效应 287
摩尔负载模式 288
Google Workflow 简介 289
Workflow 是模型—视图—控制器(MVC)模式 290
Workflow 中的执行阶段 291
Workflow 正确性保障 291
保障业务的持续性 292
小结 294

第26 章 数据完整性:读写一致 295

数据完整性的强需求 296

提供超高的数据完整性的策略 297

大二进制对象,Binary Large Object,可参见 https://en.wikipedia.org/wiki/Binary_large_object。

备份与存档 298
云计算环境下的需求 299
保障数据完整性和可用性:Google SRE 的目标 300
数据完整性是手段,数据可用性是目标 300
交付一个恢复系统,而非备份系统 301
造成数据丢失的事故类型 301
维护数据完整性的深度和广度的困难之处 303
Google SRE 保障数据完整性的手段 304
24 种数据完整性的事故组合 304
第一层: 软删除 305
第二层:备份和相关的恢复方法 306
额外一层:复制机制 308
1T vs. 1E :存储更多数据没那么简单 309
第三层:早期预警 310
确保数据恢复策略可以正常工作 313
案例分析 314
Gmail—2011 年2 月:从GTape 上恢复数据( 磁带) 314
Google Music—2012 年3 月:一次意外删除事故的检测过程 315
SRE 的基本理念在数据完整性上的应用 319
保持初学者的心态 319
信任但要验证 320
不要一厢情愿 320
纵深防御 320
小结 321
第27 章 可靠地进行产品的大规模发布 322
发布协调工程师 323
发布协调工程师的角色 324
建立发布流程 325
发布检查列表 326
推动融合和简化 326
发布未知的产品 327
起草一个发布检查列表 327
架构与依赖 328
集成 328
容量规划 328
故障模式 329
客户端行为 329
流程与自动化 330
开发流程 330
外部依赖 331
发布计划 331
可靠发布所需要的方法论 332
灰度和阶段性发布 332
功能开关框架 333
应对客户端滥用行为 334
过载行为和压力测试 335
LCE 的发展 335
LCE 检查列表的变迁 336
LCE 没有解决的问题 337
小结 338

第Ⅳ部分 管理

任何一个想要建立有效SRE团队的组织都需要格外关注培训。一个用心设计、用心 执行的培训课程,可以培训SRE在复杂和快速变动的环境下有效应对。这样的课程 可以在新员工刚入职的数周或数月内将多年积累的最佳实践和最佳策略一次灌输给 他们。请见本书第28章中的详细描述。

任何一个参与运维的人都知道,运维大型服务通常会带来很多中断性任务:生产环 境出现问题,需要更新二进制文件,不停地咨询请求等。在这样多变的环境下有效 地管理这些中断性任务是SRE必备的技能,详情请见第29章。

如果这种多变的状况持续过久,SRE团队需要从运维过载的情况中恢复过来。我们 在第30章中详细描述了一套应对流程。

第28 章 迅速培养SRE 加入on-call 341

新的SRE 已经招聘到了,接下来怎么办 341
培训初期:重体系,而非混乱 344
系统性、累积型的学习方式 345
目标性强的项目工作,而非琐事 346

培养反向工程能力和随机应变能力 347

反向工程:弄明白系统如何工作 347

工程师对他们从未见过的系统都很好奇—工作原理是什么。

统计学和比较性思维:在压力下坚持科学方法论 347

进行系统故障调试的过程很像是一种游戏:“下列哪一个东西与其他 不同”?这里的“东西”可能是内核版本、CPU架构、

随机应变的能力:当意料之外的事情发生时怎么办 348
将知识串联起来:反向工程某个生产环境服务 348
有抱负的on-call 工程师的5 个特点 349
对事故的渴望:事后总结的阅读和书写 349
故障处理分角色演习 350
破坏真的东西,并且修复它们 351
维护文档是学徒任务的一部分 352
尽早、尽快见习on-call 353
on-call 之后:通过培训的仪式感,以及日后的持续教育 354
小结 354

第29 章 处理中断性任务 355

运维负载有许多类型,基本分为三大类:紧急警报、工单,以及 其他的持续性运维活动。

管理运维负载 356
如何决策对中断性任务的处理策略 356

不完美的机器 357

流状态 357

流状态(flow state)进入这个状态可以鼓励员工真正地掌握和优化某个 他们负责的任务和项目。但是,如果有其他的事情打断他们,他们就 会失去这个状态。我们的目标是尽可能让员工在这个状态下工作。

认知流状态:富有创造性和参与感

某个人在解决问题的过程中,充 分了解问题的起因和现状,隐约感觉自己可以解决这个问题。

将一件事情做好 358

极化时间
为了限制干扰数量,我们应该减少上下文切换(指工作类型、环 境等的改变)。

实际一点的建议 359
减少中断 361
第30 章 通过嵌入SRE 的方式帮助团队从运维过载中恢复 363
第一阶段:了解服务,了解上下文 364
确定最大的压力来源 364
找到导火索 364
第二阶段:分享背景知识 365
书写一个好的事后总结作为示范 366
将紧急事件按类型排序 366
第三阶段:主导改变 367
从基础开始 367
获取团队成员的帮助 367
解释你的逻辑推理过程 368
提出引导性问题 368
小结 369

第 31 章 SRE 与其他团队的沟通与协作 370

沟通:生产会议 371

SRE发现有一种会议非常有用,我们称之为生产会议 (production meeting)。生产会议的另一个主要目 标是,通过将在生产中获取的知识应用到服务中来以便改善服务。

议程 372

  • 即将到来的生产环境变化
  • 性能指标
  • 故障。这个部分会讨论那些值得写事后总结的问题
  • 紧急警报。这部分有两个隐含的问题:这个警报发出的 时间、内容等是否合适?这个警报应该是紧急警报吗?如果对于后一 个问题的答案是否定的,那么就应该去掉这个警报。
  • 之前的待办事项。像其他任何会议一样追踪这些改 进:将待办事项分配给具体的人,并跟踪进展情况。

出席人员 373

你会发现需要参加这个会议的团队,或者很多忙碌而 重要的与会者需要你去逐个邀请。这里有一些技巧可以用来处理这些 情况:

  • 不那么活跃的服务可能只需要产品研发团队的一个代表出席, 或者仅仅是获得产品研发团队的一个承诺就够了:承诺他们会阅读和 评论会议日程。
  • 那些忙碌却重要的与会者可以通过事先提供个人反馈和引导的 方式参加

SRE 的内部协作 374

专业化是实现这一目标的一种方法,比如,团队X只会 为产品Y服务。专业化有很多优势,因为它能够大幅提高技术熟练度。 但同时专业化也是有弊端的,因为它会导致局部化,忽视大局。我们 要有一个清晰的团队章程来定义一个团队将要做什么—更重要的是不 会做什么—但这并不总是那么容易。

团队构成 375

高效工作的技术 375

书面沟通能力再强,随着时间的推移,人们对你 的印象也会逐渐淡薄成一个电子邮件地址,直到你再次出现进行直接 沟通。

SRE 内部的协作案例分析:Viceroy 376

Viceroy 的诞生 376
所面临的挑战 378

建议 379

举办一次峰会是一个解决设 计问题和目标的好机会。在中立性很重要的情况下,应该选择在一个 中立的位置举办峰会,这样可以让与会者都没有“主场优势”。

SRE 与其他部门之间的协作 380
案例分析:将DFP 迁移到F1 380
小结 382

第32 章 SRE 参与模式的演进历程 383

SRE 参与模式:是什么、怎么样以及为什么 383
PRR 模型 384
SRE 参与模型 384
替代性支持 385

PRR :简单PRR 模型 386

当SRE接到来自研发团队的生产运维接管要求时,他们需要评估该 服务的重要程度和目前团队的可用性。如果该服务的确值得SRE支持,那么SRE 会与研发团队一起启动PRR评审流程。

参与 386

该 小组负责与研发团队启动讨论。该讨论涵盖以下事项:

  • 为该服务建立一个SLO/SLA。
  • 为可能的、为了提高可靠性的破坏性设计变更制定计划。
  • 制定交接计划和培训计划。

分析 387

在这个阶段中,SRE评审者将仔 细学习该服务的一切知识,开始对其生产方面的缺陷进行分析。SRE的 目标是度量该服务自身的成熟程度,以及SRE最关注的运维方面的情 况。

改进和重构 387

下一阶段 按如下顺序进行:

  • 将每个改进建议按照其对服务可靠度的影响而排序,制定一个 优先级顺序。
  • 与研发团队讨论和协商这些建议,达成一个共识。
  • SRE和产品研发团队同时参与,并且协助对方进行重构,或者 实现额外的功能。此阶段所需要的时间和资源在各个项目上有很大不 同。这主要取决于工程师花在重构上的时间,评估该服务成熟度和复 杂度的时间,以及无数的其他因素。

培训 388

这些SRE会组织一系列的培训课程和练习。其中包括:

  • 设计概述
  • 对系统中各种请求的处理流进行深入探讨
  • 生产环境部署模式的描述
  • 对系统运维各个方面的手动练习

“接手”服务 388
持续改进 388
简单PRR 模型的演进:早期参与模型 389
早期参与模型的适用对象 389
早期参与模型的优势 390
不断发展的服务:框架和SRE 平台 391
经验教训 391
影响SRE 的外部因素 392
结构化的解决方案:框架 392
新服务和管理优势 394
小结 395

第Ⅴ部分 结束语

第33 章 其他行业的实践经验 398
有其他行业背景的资深SRE 399
灾难预案与演习 400
从组织架构层面坚持不懈地对安全进行关注 401
关注任何细节 401
冗余容量 401
模拟以及进行线上灾难演习 402
培训与考核 402
对详细的需求收集和系统设计的关注 402
纵深防御 403
事后总结的文化 403
将重复性工作自动化,消除运维负载 404
结构化和理性的决策 406
小结 407
第34 章 结语 408

附录A 系统可用性 411

水平 每年 每季度 每月 每周 每天 每小时
90% 36.5 days 9 days 3 days 16.8 hours 2.4 hours 6 minutes
95% 18.25 days 4.5 days 1.5 days 8.4 hours 1.2 hours 3 minutes
99% 3.65 days 21.6 hours 7.2 hours 1.68 hours 14.4 minutes 36 seconds
99.5% 1.83 days 10.8 hours 3.6 hours 50.4 minutes 7.20 minutes 18 seconds
99.9% 8.76 hours 2.16 hours 43.2 minutes 10.1 minutes 1.44 minutes 3.6 seconds
99.95% 4.38 hours 1.08 hours 21.6 minutes 5.04 minutes 43.2 seconds 1.8 seconds
99.99% 52.6 minutes 12.96 minutes 4.32 minutes 60.5 seconds 8.64 seconds 0.36 seconds
99.999% 5.26 minutes 1.30 minutes 25.9 seconds 6.05 seconds 0.87 seconds 0.04 seconds

附录B 生产环境运维过程中的最佳实践 412

附录C 事故状态文档示范 417

[!NOTE]
摘要:
事故处理组织架构:(参与人)

  • 目前事故总负责人:jennifer
  • ─ 运维负责人:docbrown
  • ─ 计划负责人:jennfier
  • ─ 沟通负责人:jennifer

代办列表以及已提交的工单:

事故时间线(倒序排列,时区为UTC):
2015-10-21 15:28 UTC jennifer
─ 全球服务容量提升为2倍。

附录D 事后总结示范 419

[!NOTE]
摘要:
根源问题:
触发条件:
解决方案:

附录E 发布协调检查列表 423
附录F 生产环境会议记录示范 425
参考文献 427
索引 439

posted @ 2025-03-14 22:53  liqinglucky  阅读(207)  评论(0)    收藏  举报