SRE Google运维解密 10-27章
第三部分 具体实践
应急事件处理
一旦SRE发现了系统中存在的问题,要如何解决呢?正确的解决方案不一定是当初把问题一次性修复好,而可以靠降低系统准确度、关闭一些不重要的功能,或者将用户流量导向其他没有问题的任务实例等手段暂时缓解问题。解决方案的细节肯定是和每个服务和团队相关的。但是如何有效地应对紧急问题的方法论是每个团队都适用的。
第十章 基于时间序列数据进行有效报警
Borgmon为每个监控目标记录了一些自动生成的 "合成指标",以便区分一下几种情况:
- 目标地址是否成功解析为 IP 和 端口
- 目标是否响应了一次收集请求
- 目标是否响应了一次健康检查请求
- 数据收集成功结束的时间点
第十一章 on-call轮值
如果一个服务有足够的业务需求需要更多的人,与其继续扩展当地团队(single site),我们更愿意把该团队转化为多地团队(multi site)。多地团队相比之下有以下两点优势:
- 长时间执行夜间任务对人的健康不利
- 通过限制一个团队在 on-call 轮值制度中的人员数量,可保障每个工程师对生产环境的熟悉程度
每次 on-call 值班过程中,轮值工程师必须有足够的时间处理紧急事件和后续跟进工作,例如写事后报告。
紧急事件(incident) 定义:一系列根本原因一致或者相关的事件和报警信息,这些事件应该在同一个事后报告中讨论。
在应急事件处理过程中,最理想的方法是这样:在有足够数据支撑的时候按步骤解决问题,同时不停地审视和验证目前所有的假设。
让 on-call SRE 知道他们可以寻求外部帮助,对减轻 on-call 压力也很有帮助。最重要的资源有:
- 清晰的问题升级路线
- 清晰定义的应急事件处理步骤
- 无指责,对事不对人的文化氛围
虽然给一个非常安静的系统 on-call 值班是很幸福的事情,但是当一个系统太稳定,或者SRE on-call 的周期太长会发生什么呢? SRE 团队运维压力不够也是一个不良现象。长时间不操作生产环境会导致自信心问题,包括自信心太强以及自信心不够。这些现象只有在下一次发生问题时,才会显现出来。
为了避免这种问题,应该控制 SRE 团队的大小,保证每个工程师每个季度至少参与 on call 一次,最好两次。这样可以保证团队成员有足够的生产环境操作经验。
第十二章 有效的故障排查手段
值得警惕的是,理解一个系统应该如何工作并不能使人成为专家。只能靠调查系统为何不能正常工作才行。
系统正常,只是该系统无数异常情况下的一种特例。
新手们常常不能有效地进行故障排查,是因为这个过程理想情况下同时需要两个条件
1.对通用的故障排查过程的理解 (不依靠任何特定系统)
2.对发生故障的系统的足够了解
理论
从理论上讲,我们将故障排查过程定义为反复采用假设-排除手段的过程
常见的陷阱
- 关注了错误的系统现象,或者错误地理解了系统现象的含义。这样会在错误的方向上浪费时间。
- 不能正确修改系统的配置信息、输入信息或者系统运行环境,造成不能安全和有效地测试假设。
- 将问题过早地归结为极为不可能的因素 (例如认为是宇宙射线造成数据变化,虽然有可能发生,但是并不应该在解决问题初期做这个假设),或者念念不忘之前曾经发生过的系统问题,认为一旦发生过一次,就有可能再次发生。
- 试图解决与当前系统问题相关的一些问题,却没有认识到这些其实只是巧合,或者这些问题其实是由于当前系统的问题造成的。(比如发现数据库压力大的情况下,环境温度也有所上升,于是试图解决环境温度问题。)
要避免第一点和第二点,需要更详细地学习系统的运行原理,同时了解分布式系统运行得基本模式。
要避免第三点,需要记住,不是所有的失败情况的出现概率都相同,而且尤其要注意,当所有可能都存在的时候,我们应该优先考虑最简单的解释
最后,我们要记住,相关性不等于因果关系
在大型问题中,你的第一反应可能是立即开始故障排查过程,试图尽快找到问题根源这是错误的!不要这样做。
正确的做法应该是:尽最大可能让系统恢复服务。这可能需要一些应急措施,比如,将用户流量从问题集群导向其他还在正常工作的集群,或者将流量彻底抛弃以避免连锁过载问题,或者关闭系统的某些功能以降低负载。缓解系统问题应该是你的第一要务。在寻找问题根源的时候,不能使用系统的用户并没有得到任何帮助。当然,快速定位问题时仍应该及时保存问题现场,比如服务日志等,以便后续进行问题根源分析时使用。
在初级飞行员的课程中讲到,在紧急情况中,飞行员的首要任务是保持飞机飞行。相比保证乘客与飞机安全着陆,故障定位和排除是次要目标。这种方法也同样适用于计算机系统:如果一个 Bug 有可能导致不可恢复的数据损坏,停止整个系统要比让系统继续运行更好。
检查
我们必须能够检查系统中每个组件的工作状态,以便了解整个系统是不是在正常工作
日志是另外一个无价之宝。在日志中记录每个操作的信息和对应的系统状态可以让你了解在某一时刻整个组件究竟在做什么(日志记录系统最好能够按需、快速、有选择启用)
对问题现象的解析
现象:一个Spariner 集群出现延迟过高的情况,RPC请求超时
为什么:Spanner 服务器的任务实例把 CPU占满了,无法处理用户发来的请求。
哪里:Spanner服务器的CPU消耗在了哪里?通过采样 (profiling)得知该任务正在将日志记录排序,写入磁盘
哪里:这段排序代码中的哪部分在消耗资源?是在一段正则表达式的计算过程中
解决方案:重写该正则表达式,避免使用回潮 (backtracking)。在代码中寻找类似的问题。考虑使用RE2、该类库保证不使用回溯,同时保障运行时间与输入呈线性关系
最后一个修改
计算机系统有惯性存在:我们发现,一个正常工作的计算机系统会维持工作,直到某种外力因素出现,例如一个配置文件的修改,用户流量的改变等。检查最近对系统的修改可能对查找问题根源很有帮助。
测试和修复
- 一个理想的测试应该具有互斥性,通过执行这个测试,可以将一组假设推翻,同时确认另外一组假设。在实际执行中,这比较难。
- 先测试最可能的情况:按照可能发生的顺序执行测试,同时考虑该测试对系统的危险性。先测试网络连通性,再检查是否是最近的配置文件改变导致用户无法访问某机器可能更合理。
- 某项测试可能产生有误导性的结果。例如:防火墙规则可能只允许某些特定IP访问,所以在你的工作机上 ping 数据库可能会失败,而实际从应用服务器上ping数据库可能是成功的。
- 执行测试可能会带来副作用。举例说明:让一个进程使用更多 CPU 可能会让某些操作更快,也可能会导致数据竞争问题更容易发生(单线程与多线程运行)。同样的,在运行中开启详细日志可能会使延迟问题变得更糟,同时也让你的测试结果难以理解:是问题变得更加严重了,还是因为开启详细日志的原因?
- 某些测试无法得出准确的结论,只是建议性的。死锁和数据竞争问题可能是非常难以重现的,所以有的时候你并不能找到非常确切的证据。
将你的想法明确地记录下来,包括你执行了哪些测试,以及结果是什么。尤其是当你处理更加复杂的问题时,良好的文档可以让你记住曾经发生过什么,可避免重复执行。如果你修改了线上系统,例如给某个进程增加了可用资源。系统化和文档化这些改变有助于将系统还原到测试前的状态,而不是一直运行在这种未知状态下。
治愈
理想状况下,现在你已经将一系列可能的错误原因减少到了一个。下一步,我们想要证明这就是问题根源。在生产环境中试图通过重现一个原因而明确地证明它就是问题的原因是很困难的。因为如下几个原因,我们经常只能发现可能的原因。
- 真实系统通常是系统复杂度。很有可能有多个因素共同作用导致系统问题。路径依赖的,也就是说,它们必须处于一个特定状态下问题才会发生。
- 在生产环境中重现某个问题也许是不可能的。要么因为将系统置于某种问题状态过于复杂,或者是系统过于重要,不能再出问题。如果有一套非生产环境的复制系统可能好一些,但是需要额外付出一定的成本。
当你最终确定了某个因素是问题根源时,应该将系统中出错的部分,你是如何定位问题的,和你是如何修复问题的,如何防止再次发生等写下来。这就是事后总结。希望这时候系统是活着的! (事后总结也称为验尸报告,但是这里是在问题解决后才写的,服务已经恢复。)
第十三章 紧急事件响应
案例一:变更部署带来的紧急事故
细节
在某个星期五,一个防滥用基础服务(anti-abuse)的新版配置文件被推送到所有的服务器上。这个服务和 Google 所有对外服务都有直接联系。这个新版配置文件触发了一个Bug,导致这些对外服务都进入了崩溃循环 (crash-loop)。因为 Google 内部很多基础服务也依赖于这些内部服务,所以导致很多内部应用程序也失去了响应。
事故响应
几秒内,各种监控就开始报警,声称某些网站失去了响应。一些 on-call 工程师同时发现公司内网好像出现了问题,于是他们都前往一个专门的灾难安全屋(panic room)。这个房间中有 Google生产环境的专线连接。他们意外地发现,越来越多的人因为网络问题来到了这里。
在配置文件发布的 5 分钟后,负责发布这个配置的工程师也发现公司内网出现了问题但是还没意识到更大范围的生产系统问题。该工程师发布了一份修正过的配置文件,以便将之前的问题回滚。此时,各项服务逐渐开始恢复。
在第一次发布的 10 分钟后,on-call 工程师按照内部应急流程宣告进入紧急状态。他们开始通知公司内的其他部门目前的情况。负责发布配置的工程师告诉 on-all 工程师这次事故可能是由于他发布的配置文件造成的,而且目前已经回滚了。但是,有些服务遇到了由于最初的事故导致的另外的 Bug 或者错误的配置等影响,一个小时后才能恢复。
事后总结
做的好的地方:
以下几个因素使得很多Google 内部系统及时恢复了。
首先,监控系统及时检测和汇报了问题。但是这里应该记录下来,我们的监控系统还是存在问题:报警信息不停地重复报警,让 on-call 工程师难以应对,导致在正常的和紧急的通信通道中充斥了大量垃圾信息。
问题被检测到之后,应急响应流程处理得当,其他人得到了清晰和及时的事态更新。我们的带外通信系统 (out-of-band,指专线数据中心连接) 保证了在复杂软件问题下,每个人都能保持连接。这次经历提醒了我们,SRE 为什么要保持一些非常可靠的、低成本备份访问系统运行,因为我们在这种情况下就会用到!
在这些带外通信系统之外,Google 还有命令行工具和其他的访问方式确保我们能够在其他条件无法访问的时候进行更新和变更回滚。这些工具和访问方式在这次事故中起到重大作用,但是工程师应该更加频繁地测试,以便更为熟悉它们。
Google 的系统架构体系提供了另外一层保护,这次受影响的系统包含了限速机制,限制他们给新客户端分发配置变更的速度。这些限速措施可能抑制了崩溃循环的速度,使得某些任务可以在崩溃之前还可以处理一些服务器请求,从而避免了进入彻底不可用的状态。
最后,我们不应该小看运气这个因素。这次我们能够迅速解决问题是因为进行部署变更的工程师恰好在监控某些实时通信频道,这并不是发布过程中要求的。正因为如此,这个工程师注意到在变更推送结束后,频道里出现了大量的公司网络访问故障报告,从而迅速回退了该配置。如果配置没有这么快地被回退,这项事故可能会持续相当长的时间同时变得更难解决
我们从中学到的:
在之前的部署中,导致问题的这项新功能经历了一个完整的部署试验(Canary) 周期却没有触发该 Bug,因为在那次测试中配置文件中没有用到一个非常特别、很少用到的关键词。这次触发问题的变更,并没有被认为是非常危险的,导致这项改动仅仅经历了一个简单的部署试验过程。当这次变更在全球部署的时候,这个没有经过测试的关键词 / 新功能组合导致了灾难的发生。
具有讽刺意味的是,我们本来计划在下个季度提高部署测试流程和自动化的优先级。这次事故的发生直接将他们的优先级提高了,同时强调不管风险看起来有多小,也要经过严格完整的部署测试。
案例二:流程导致的严重事故
细节
在一项常规自动化测试中,该测试针对同一个集群(马上即将退役的)发送了两个连续的下线请求(turndown)。在处理第二个下线请求时,自动化系统中的一个非常隐蔽的Bug将全球所有数据中心的所有机器加到了磁盘销毁 (diskerase)的队列中,这导致硬盘数据被清空。
灾难响应
在第二个下线请求提交不久之后,on-call工程师收到一个警报,声称第一个小型数据中心的全部机器都被下线了,即将退役。工程师的调查显示,这些机器已经被转移到了磁盘销毁队列中。所以按照正常流程,on-call 工程师将用户流量导向了其他地区 (drain)。因为这些机器的硬盘已经被清空了,为了避免这些请求失败,on-call工程师将用户流量导向了其他正常工作的地区。
不久之后,全球各地数据中心都发出了报警。on-call工程师收到报警后,将整个团队的自动化工具全部停止,避免问题进一步发展。随后,他们停止或者暂停了更多的自动化工具,以及常规的生产环境维护活动。
在一个小时之内,所有用户流量都被导向其他的地方了。虽然用户可能面临延迟升高等问题,但是他们的请求还是能够被正常处理的。这次事故总算结束了。
现在最难的部分开始了:恢复。有些网络连接汇报堵塞得非常严重,所以网络工程师在网络关键节点部署了一些缓解措施。在这些节点中的某个数据中心被选中为第一个浴火重生。三个小时后,经过几个工程师的努力,这个数据中心被成功重建了,可以再次接受用户请求了。
美国团队将工作交接给了他们的欧洲伙伴团队。SRE 设计了一个利用手动步骤快速执行重建操作的计划。整个团队分为三部分,每部分负责整个手工重建计划中的一步。在三天内,大部分服务器都恢复了服务,其余没有恢复的都将在下个月或者下两个月内恢复。
事后总结
做的好的地方:
小型数据中心的下线请求处理过程非常高效和完美。从开始到结束,不到一个小时的时间内大量的小型数据中心都被成功地下线以及进行安全的硬盘擦除。
虽然下线自动化迅速将对应的站点监控系统也干掉了,但是 on-call 工程师成功地将这些改动快速恢复。这一点对他们评估事故严重程度提供了帮助。
我们从中学到的:
这次事故的根源在于自动化系统对它发出的命令缺乏合适的合理性检查。当自动化系统第二次运行,获取机柜列表时得到了一个空白回应。该自动化系统没有抛弃这个回复,而是在整个机器数据库(Google Machine Database 记录了生产系统中的全部机器列表)上运行了一个空白过滤,导致将数据库中所有的机器都转移到了磁盘擦除队列中。有的时候零就等于全部。机器数据库响应了这个请求,于是其他的下线工作流开始迅速执行起来。
所有的问题都有解决方案
时间和经验一再证明,系统不但一定会出问题,而且会以没有人能够想到的方式出问题。Google 学到的最关键的一课是,所有的问题都有对应的解决方案,虽然对一个面对着疯狂报警的工程师来说,它可能不是那么显而易见。如果你想不到解决办法,那么就在更大的范围内寻求帮助。找到更多团队成员,寻求更多的帮助,做你需要做的一切事情但是要快。最高的优先级永远是将手头问题迅速解决。很多时候,触发这个事故的人对事故了解得最清楚,一定要充分利用这一点。
非常重要的是,一旦紧急事件过去之后,别忘了留出一些时间书写事后报告
第十四章 紧急事故管理
无流程管理的紧急事故
有几个常见的问题导致了整个事故的失控
- 过于关注技术问题
- 沟通不畅
- 不请自来
紧急事故的流程管理要素
分配角色:
- 事故总控(incident command):掌握这次事故的概要信息。他们负责组建事故处理团队,按需求和优先级将一些任务分配给团队成员。未分配的职责仍由事故总控人负责。如果有必要的话,他们要负责协调工作,让事务处理团队可以更有效地解决问题,比如代申请访问权限、收集联系信息等
- 事务处理团队(operational work):事务处理团队负责人在与事故总控负责人充分沟通的情况下,负责指挥团队具体执行合适的事务来解决问题。事务处理团队是在一次事故中唯一能够对系统做修改的团队。
- 发言人(communication):该人是本次事故处理团队的公众发言人。他的职责包括向事故处理团队和所有关心的人发送周期性通知(通常以电子邮件形式),同时可能要负责维护目前的事故文档,保证其正确性和信息的及时性。
- 规划负责人(planning):规划负责人负责为事务处理团队提供支持,负责处理一些持续性工作,例如填写Bug 报告记录系统,给事务处理团队订晚餐,安排职责交接记录。同时负责记录在处理过程中对系统进行的特殊操作,以便未来事故结束后能够复原。
实时事故状态文档
事故总控负责人最重要的职责就是要维护一个实时事故文档。该文档可以以 wiki的形式存在,但是最好能够被多人同时编辑。
使用模板来填写这个文档能容易一些,同时将最新信息发布在文档顶部也有助于提高可用性。在事后总结时还要使用这篇文档。
附录C 事故状态文档示范
明确公开的职责交接
超出工作时间以后,事故总控负责人的职责能够明确、公开地进行交接是很重要的。如果你将事故总控职责交接给另外一个地区的人时,可以通过电话或一次视频会议将目前的情况交接给他。当新的事故总控负责人了解了目前事故情况时,当前事故总控负责人必须明确地声明:"从现在开始由你负责事故总控,请确认。" 当前事故负责人在得到明确回复之前不得离开岗位。交接结果应该宣布给其他正在处理事故的人,明确目前的事故总控负责人。
什么时候对外宣布事故
先宣布事故发生,随后找到一个简单解决方案,然后宣布事故结束,要比在问题已经持续几个小时之后才想起流程管理更好。
如果下面任何一条满足条件,这次事故应该被及时宣布:
- 是否需要引入第二个团队来帮助处理问题?
- 这次事故是否正在影响最终用户?
- 在集中分析一小时后,这个问题是否依然没有得到解决?
事故流程管理最佳实践
- 划分优先级:控制影响范围,恢复服务,同时为根源调查保存现场。
- 事前准备:事先和所有事故处理参与者一起准备一套流程
- 信任:充分相信每个事故处理参与者,分配职责后让他们自主行动
- 反思:在事故处理过程中注意自己的情绪和精神状态。如果发现自己开始惊慌失措或者感到压力难以承受,应该寻求更多的帮助。
- 考虑替代方案 :周期性地重新审视目前的情况,重新评估目前的工作是否应该继续执行,还是需要执行其他更重要或者更紧急的事情。
- 练习:平时不断地使用这项流程,直到习惯成自然
- 换位思考:上次你是事故总控负责人吗?下次可以换一个职责试试。鼓励每个团队成员熟悉流程中的其他角色
第十五章 事后总结:从失败中学习
学习是避免失败的最好办法
协作和知识共享
-
实时协作:使得写作过程可以很快地收集数据和想法。这在事后总结早期很有帮助。
-
开放的评论系统:使大家都可以参与进来提供解决方案,以及提高对事故处理细节的覆盖程度
-
邮件通知可以在文档中给其他用户发消息,或者引入其他人来共同填写文档。
书写事后总结的过程还包括正式的评审和发布过程。在实践中,团队首先内部发布,同时有目的地找一些资深工程师来评估文档的完整程度。评审的条件包括如下几项:
- 关键的灾难数据是否已经被收集并保存起来了?
- 本次事故的影响评估是否完整?
- 造成事故的根源问题是否足够深入?
- 文档中记录的任务优先级是否合理,能否及时解决了根源问题?
- 这次事故处理的过程是否共享给了所有相关部门?
初期评审结束之后,该篇事后总结会在更大范围内公布。通常是在更大范围的研发部门内部传阅,或者是以内部邮件列表形式传播。我们的目标是将事后总结传播得越广越好,传递给所有能够以此获益的团队和部门。Google 针对任何可以定位个人的信息有严格管控规则,事后总结这种内部文档也不允许包括这样的信息。
一旦所有的事故参与者都对文档和其中的代办事项表示了肯定,这篇事后总结会被添加到该团队或者整个组织的文档汇总中。透明化的共享机制保证了每个人都可以很容易地找到和学习以前的事故。
最佳实践:所有的事后总结都需要评审
未经评审的事后总结还不如不写。为了保障每个写完的草稿都得到评审,我们鼓励定期举行评审会议。在这些会议上,我们应该注意着重解决目前文档中的疑问和评论,收集相关的想法,将文档完成。
建立事后总结文化
- 本月最佳事后总结:通过每周一次的新闻邮件,与整个组织共享一篇有趣并且质量很高的事后总结
- Google+ 事后总结小组:本小组共享和讨论内部与外部的事后总结,同时包括一些最佳实践和事后总结的评论文章。
- 事后总结阅读俱乐部:某团队经常性地组织阅读俱乐部。在这项活动过程中,所有参与者和未参与者 (甚至是新来的工程师)共同开发式地过论一篇有趣或者很有影响力的事后总结,包括事件的发生过程,学习到的经验教训,以及善后处理。通常,我们讨论的是几月前甚者几年前的事后总结。
- 命运之轮:在这个活动中,我们将之前的某篇事后总结的场景再现-批工程师负责扮演这篇文档中提到的各种角色。经常,当时的事故总控负责人也参与其中,确保这次演习越真实越好。
在引入事后总结机制的时候,最大的阻力来源于对投入产出比的质疑。下面的策略可以帮助面对这些挑战:
- 逐渐引入事后总结流程。首先进行几次完整的和成功的事后总结,证明它们的价值,同时帮助确定具体书写事后总结的条件。
- 确保对有效的书面总结提供奖励和庆祝。不光通过前面提到的公开渠道,也应该在团队或个人的绩效考核中体现。
- 鼓励公司高级管理层认可和参与其中。Larry Page(Google 创始人之一)经常称赞事后总结的价值之高!
最佳实践:收集关于事后总结有效性的反馈
我们倾向于解决新问题并将创新在内部共享。我们经常在团队内部搞调查问卷,以了解事后总结流程是否在合理地支持他们的工作,以及如何改进。我们问的问题有:团队文化是否支持你的工作?书写事后总结是否引入了太多杂事?你们的团队有什么最佳实践可以分享?这些调查结果可以给平时很忙的一个机会去提供有效性的改进和反馈意见。
附录D 事后总结示范
第十六章 跟踪故障
提高可靠性的唯一可靠的方法论是建立一个基线 (baseline),同时不断跟踪改变。
将多个报警信息“聚合”成一个单独的故障能够有效解决这个问题。
加标签:标签基本上没有格式要求,都是独立的“单词”。冒号(😃,被认为是语义性分隔符,所以这实际上隐含提倡了一种层级结构的命名空间体制,以及一些自动化处理。(cause:network)
标签也可以被解析成一个链接(比如 “bug:76543” 将被解析成Bug跟踪系统的一个链接)。
第十七章 测试可靠性
测试的数量直接取决于所服务系统的可靠性要求。随着代码的测试覆盖度上升,每次改动的不确定性和降低系统可靠度的可能性都降低了。足够的代码测试覆盖度可以让我们对系统做出更多的改动。
系统测试:冒烟测试,性能测试(通过某个系统测试的变形来保证整个系统的性能自始至终在可接受范围内),回归测试(保证之前的Bug不会重现)
压力测试:
- 数据库容量满到什么程度,才会导致写请求失败
- 向某应用每秒发送多少个请求,将导致应用过载并导致请求处理失败
金丝雀测试
针对危险性高的软件设立防护边界
第十八章 SRE部门中的软件工程实践
Auxon(自动化容量规划工具)案例分析
传统的容量规划方法
- 收集对未来项目需求的预测(需要多少资源?这些资源什么时候需要,以及它们需要在什么物理位置?)
- 使用我们今天拥有的最佳数据来计划明天。
- 预测长度一般是几个季度到几年。
- 制定资源的采购、构建和分配计划
- 基于上述预测,我们如何能最好地满足未来的资源需求?需要在“哪里”构建“多少”资源?
- 评审,并且批准这个计划
- 这项计划是不是合理的?这项计划是否和预算相符,是否符合产品的期望与技术的要求?
- 部署和配置对应的资源
- 一旦资源最终到位(有可能是在一段时间内),哪些服务最终会使用该资源?如何能够将底层的CPU、磁盘等资源合理配置给服务使用?
传统的容量规划方法的缺点
- 不可靠性:传统的容量规划过程容易产生出一个非常不可靠的资源配给计划,该计划会由于出现某些看起来很小的改动而全盘失效
- 耗时巨大,同时不够精确
解决方案:基于意图的容量规划
列出你的要求,而不要拘泥于具体实现细节
这个规划过程是将服务的依赖和资源的参数(也就是意图)用编程的方式记录下来。同时利用一个算法自动产生资源的配给方案,包括在哪个集群中将多少资源配置给哪个服务这些细节。如果需求、供给,或者某个服务的产品需求发生变化,我们可以随时重
新生成这项计划,以便更好地分配资源。
由于这里记录了每个服务的真实需求和它们的选择自由度信息,所产生的容量规划在面临变动的时候非常可靠,我们可以产生出一个满足最多要求的最优解。
另外一个好处是,用计算优化的方式来将容量的需求和实际供给对应,可以提供更高的计划精确度,最后可以给整个组织降低更多的成本。最优解的计算仍然并不能称为完全解决,因为某些配置问题仍具有 NP-hard 的计算复杂度。但是我们现在的算法已经能够找到一些已知的局部最优解。
举例:
- 我需要50个CPU的资源,必须在集群X、Y、Z中,为服务Foo使用(这是一个具体的资源请求,但是,为什么我们需要这么多资源,同时一定要在这三个集群中?)
- 我需要50个CPU的资源,在地理区域YYYY中的任意三个集群中,为服务Foo使用(这项请求增加了更多的选择自由度,也更容易被满足,但是仍然没有解释这项请求背后的原因,为什么我们需要这么多资源,以及为什么需要三个集群?)
- 我想要满足Foo在每个地理区域的需求增长,同时保障 N+2 冗余度(现在有了更多的选择自由度,同时我们可以更好地理解如果 Foo 没有获得相应的资源,究竟会造成什么后果。)
- 我们想要将Foo以 99.999% 的可靠度运行(这是相对更抽象的一个需求,当容量得不到满足时的后果也更清楚了:可靠性会下降。而且我们从中获得了更多的选择自由度:也许以 N+2 运行并不是足够的,或者并不是最优化的情况,其他的某种部署计划是更合适的。)
所以,我们应该在容量规划过程中采用哪个级别的抽象呢?理想情况下,所有上述级别都应该包括,服务提供的“意图”越多,它们得到的好处也就越大。Google 的经验告诉我们,一般的服务在达到第三步的时候获得的好处最大: 提供足够的选择自由度,同时可以将需求得不到满足的后果用高阶的、易理解的方式表达。某些特别复杂的项目可能需要向第四步努力。
数据信息(Performance Data) 描述了某个服务的规模化能力。针对集群Y中的需求X需要多少单元的依赖服务Z资源?这些数据可以根据服务的成熟程度用不同的方法获得某些服务是通过压力测试得到的,某些是从过去的性能数据中得出的。
每个服务的需求预测数据(Per-Service Demand Forecast Data)描述了针对服务的需求预测信息。某些服务根据它们需求的预测信息推断资源使用量一一分大陆区域预测的 QPS信息。不是所有的服务都能这样预测需求 (例如存储服务 Colossus),某些服务的需求仅仅来源于依赖它们的服务。
资源供给(Resource Supply) 提供了基础资源的可用性,举例来说,未来某个时间点可用的物理服务器的总量。以线性规划术语来说,资源供给是上限 upper bound,限制了服务的增长和放置选择。我们的终极目标是,在服务意图配置的框架内最优化资源供应的使用。
资源价格(Resource Pricing)提供了基础资源的成本信息。举例来说,物理服务器的成本可能根据所在数据中心的位置和电源成本差别很大。在线性规划术语中,这些价格代表了总体资源的成本,也是我们要最优化的“目标”
意图配置信息 (Intent Config)是向Auxon 输基于意图的信息的关键渠道。这里定义了每个服务,以及服务之间的依赖关系。这个配置文件最终会成为其他组件的黏合剂,将其他的组件结合起来。这个部分目前被设计为人类可读和可配置的格式。
Auxon 配置语言引擎(Auxon Configuration Language Engine)处理从意图配置信息中获取到的信息,将信息转化为机器格式,也就是 Auxon 求解器所需要的 Protocol buffer 格式。同时,这个组件会进行一些简单的正确性检查。这个组件的作用就是在人类可维护的配置信息与机器可用的格式之间进行转换。
Auxon 求解器(Auxon Solver)是整个工具的大脑。它根据从Auxon 配置语言引擎中获得的优化请求建立起一个庞大的混合整型线性规划程序。这个工具的扩展性非常好,可以同时运行在 Google 集群内的几百台甚至几千台机器上进行并行求解。除了针对混合整型线性规划的求解程序之外,Auxon 求解器还包括任务的分发、工作池的维护,以及决策树相关的程序。
资源分配计划 (Allocation Plan)是 Auxon 求解器的最后产物。它描述了在何处的何种资源应该分配给哪个服务。这个计划就是基于意图的资源规划的实现细节。该分配计划同时包括了哪些资源需求无法得到满足一一例如,某个需求由于资源短缺无法得到满足,或者资源选择条件太过严格而导致无法满足。
提升了解程度,推进采用率
不要低估提高人们对该产品了解程度的难度一-通常发一封公告邮件或者做一个简单的演示是不够的。向大型团队推广内部软件工具需要以下几点:
- 持续的和完整的推广方案
- 用户的拥护。
- 资深工程师和管理层的赞助,因为他们看到了项目的实用潜力。
在开发过程中,时刻从用户角度出发来设计对提高可用性很重要。使用工具的工程师可能没有时间和精力去通过源代码学习如何使用一个工具。虽然内部用户相对来说比较能够容忍界面上的不足之处,适当地提供文档还是有必要的。
设立期望值
当一个在问题领域已经有多年经验的工程师设计一个产品时,我们非常容易陷入到对完美的最终产物的幻想中去。但是,给产品设计一个最小成功条件,或者是最小可行产品(MVP)是很重要的。一个工程项目如果承诺了太多、太快,而无法做到,很容易丧失可信度。同时,如果一个项目无法产生出足够有吸引力的结果,可能没有办法找到足够的人来试用。通过递进式的、稳定的、小型发布可以提升用户对项目的信心。
在 Auxon 案例中,我们通过平衡长期计划和短期修复来提高迭代速度。我们向用户承诺:
- 任何试图使用该产品(包括配置等)的团队,都可以马上通过这个产品消除需要手工整合短期资源请求的痛苦过程。
- 随着Auxon 的新功能不断增加,同样的配置文件可以保持不变,并且能提供更多的节约长期成本的好处。这个项目计划图使得用户可以很快地确定他们目前的用例是否还没有实现。同时,Auxon 的选代式开发流程可以很快地修改开发优先级或者制定新的里程碑
识别合适的用户
第十九章 前端服务器的负载均衡
搜索请求来说最重要的变量是延迟(latency)
视频上传来说最重要的变量是吞吐量(throughput)
- 搜索请求将会被发往最近的、可用的数据中心一评价条件是数据包往返时间RTT),因为我们想要最小化该请求的延迟
- 视频上传流将会采取另外一条路径一也许是一条目前带宽没有占满的链路来最大化吞吐量,同时也许会牺牲一定程度的延迟
第二十章 数据中心内部的负载均衡系统
从一个客户端的视角来看,某个后端任务可能处于下列任一种状态中:
- 健康
- 拒绝连接
- 跛脚鸭:后端任务正在监听端口,并且可以服务请求,但是已经明确要求客户端停止发送请求
第二十一章 应对过载
应对过载的一个选项是服务降级: 返回一个精确度降低的回复,或者省略回复中一些需要大量计算的数据。例如:
- 平时在整个文档库中进行搜索,以针对某个查询返回最佳结果。而过载情况下仅仅在文档库的一小部分中进行搜索
- 使用一份本地缓存的、可能不是最新的数据来回复,而不使用主存储系统
第二十二章 处理连锁故障
防止软件服务器过载
- 使用负载压力测试得出服务器的极限,同时测试过载情况下的失败模式
- 提供降级结果
- 在过载情况下主动拒绝请求
- 上层系统应该主动拒绝请求
- 进行容量规划
第二十三章 管理关键状态:利用分布式共识来提高可靠性
CAP理论
BASE-基本可用、软状态,最终一致性
系统设计师不能通过牺牲正确性来满足可靠性或者性能的要求
paxos
第二十四章 分布式周期性任务系统(略)
第二十五章 数据处理流水线(略)
第二十六章 数据完整性:读写一致
备份与存档
备份与存档最重要的区别就是,备份是可以直接被应用程序重新加载。
存档的目的是将数据长时间安全保存,以满足审核、取证和合规要求
数据完整性是手段,数据可用性是目标
交付一个恢复系统,而非备份系统
针对系统进行备份是一个长期被忽视、被拖延的系统管理任务。任何人都不会将备份作为一个高优先级任务进行一一备份需要长期消耗时间和资源,却不能带来任何现在可见的好处。
- 各团队需要为不同的失败场景定义一系列数据可用性SLO
- 各团队需要定期进行演练,以确保他们有能力满足这些SLO
造成数据丢失的事故类型
根源问题:某种无法恢复的用户数据丢失是由以下几个因素造成的:用户行为、管理员的错误应用程序的 Bug、基础设施中的问题、硬件故障和部署区的大型事故。
影响范围:有些数据丢失是大规模的,同时影响很多实体。有些数据丢失是非常有针对性的,仅仅是一小部分用户的数据损坏或者丢失。
发生速度:有些数据丢失是一瞬间造成的(例如,100 万条数据在一次操作中被替换成了 10条)。而有些数据丢失是缓慢持续进行的 (例如,每分钟丢失 10 条数据,但是持续了一周时间)。
Google SRE 保障数据完整性的手段
24种数据完整性的事故组合
确保数据恢复策略可以正常工作
- 持续针对数据恢复流程进行测试,把该测试作为正常运维操作的一部分
- 当数据恢复流程无法完成时,自动发送警报。
数据恢复计划中需要覆盖的点是很多的:
- 备份数据是否是完整的、正确的一一还是空的?
- 我们是否有足够的物理机资源来完整地完成整个恢复过程:包括运行恢复任务本身,真正恢复数据,以及数据后处理任务?
- 整个数据恢复过程能否在合理的时间内完成?
- 是否在数据恢复过程中监控状态信息?
- 恢复过程是否依赖于某些无法控制的元素一一例如某个不是 24x7 随时可以使用的异地存储媒介?
评估问题严重性
定位Bug和数据恢复的并行进行
解决根源问题
定期重新检查和重新审核
第二十七章 可靠地进行产品的大规模发布
发布协调工程师(LCE)
- 审核新产品和内部服务,确保它们和 Google 的可靠性标准以及最佳实践一致,同时提供一些具体的建议来提升可靠性
- 在发布过程中作为多个团队之间的联系人
- 跟进发布所需任务的进度,负责发布过程中所有技术相关的问题作为整个发布过程中的一个守门人,决定某项发布是否是“安全的”
- 针对 Google 的最佳实践和各项服务的集成来培训开发者,充分利用内部的文档和培训资源来加速开发。
LCE团队的成员会在整个服务生命周期的不同阶段进行审核(audit)工作
附录E 发布协调检查列表