Google SRE 指导思想

来源:互联网 发布:保姆虐童什么心态知乎 编辑:程序博客网 时间:2024/05/07 11:02
第二部分:指导思想

一、拥抱风险
Marc Alvidrez

1、管理风险
不可靠的系统会很快侵蚀用户的信心,所以我们想要减少系统故障的几率。
然而,经验表明,在构建系统的过程中,可靠性进一步提升的成本并不是线性增加的——可靠性的下一个改进可能比之前的改进成本增加 100 倍。
高昂的成本主要存在于以下两个维度。
  • 冗余物理服务器 / 计算资源的成本
  • 机会成本,这类成本由某一个组织承担,当该组织分配工程资源来构建减少风险的系统或功能
在 SRE 团队中,管理服务的可靠性很大程度上是通过管理风险来进行的。明确将运维风险与业务风险对应起来,会努力提高一项服务的可靠性,但不会超过该服务需要的可靠性,这样会浪费为系统增加新功能、清理技术债务或者降低运营成本的机会。
从某种意义上来说,Google 把可用性目标同时看作风险的最小值和最大值,既通过各种手段保障服务保持在可用性目标之内,又不愿因为提供高出目标很多的运维服务而支出更多的成本。

2、度量服务的风险
  • 基于时间的可用性:计划外停机时间,这个指标对于大多数服务而言,最直接的能够代表风险承受能力。
    • 一个可用性目标为99.9%的系统能最多在一年中停机8.76小时;
    • 一个可用性目标为99.99%的系统能最多在一年中停机52.56分钟;
  • 基于请求成功率的服务可用性:可用性=成功请求数/总的请求数,例如一个每天可用性目标为 99.99%的系统,一天要接受 2.5M 个请求。它可以在每天出现 250 个错误的同时仍然达到预计的可用性目标。
通常,Google会为一项服务设定季度性的可用性目标,并且每周甚至每天对性能进行跟踪。 这个策略使得SRE需要通过寻找、跟踪和调整重要的、不可避免的偏差来使服务达到一个高层 次的可用性目标。

3、服务风险容忍度
怎样才能识别消费者服务和基础设施服务的风险耐受水平。
  • 辨别消费者服务的风险容忍度,可以从以下几点着手
    • 服务的可用性目标水平,该服务是否直接关系到收入,竞争对手提供的服务水平如何
    • 故障的类型,不同类型的失败对服务有什么不同的影响,服务是否有可接受的维修窗口,在维修窗口中发生的发生的服务故障是否可以视为计划内停机时间
    • 成本,在提高一个9的运维水平后,收益会增加多少,这部分额外增加的收入是否可抵消为此所付出的维护成本
    • 服务延迟,服务对延迟是否敏感,服务延迟要求是什么
  • 辨别基础设施服务的风险容忍度,基础设备服务包括公司内部的软硬件基础服务,SQL/NOSQL数据服务,文件系统服务等
    • 可用性目标水平,识别不同客户对基础设施服务的使用需求和风险容忍度
    • 故障的类型,低延迟客户和高吞吐量客户的使用需求是矛盾的,也就是说一个满足低延迟客户需求的基础设施服务,意味着会成为关注高吞吐的客户的故障
    • 成本,一种在符合成本效益条件下能够满足这些竞争性约束的方式就是将基础设施分割,并在多个独立的服务水平上提供基础设施服务。

4、使用错误预算
Google的研发小组与SRE运维小组之间也会在以下工作的协作中产生紧张局势。
  • 软件对故障的容忍度,对意外事件的容忍度有多高?做得太少,只能设计出一个脆弱无用的产品;做得太多,我们的产品可能没有人会使用,但却运行非常稳定。
  • 测试,没有足够的测试,可能会造成各种令人尴尬的故障,而过于强调测试则可能会失去市场先机。
  • 发布频率,每一次发布都是有风险的,我们应该花多少时间在减少风险上?
  • 金丝雀测试的持续时间和范围大小
我们的目标是定义一个双方都同意的客观指标,该指标可以用来指导研发、运维之间谈判的方向。一项决策越是基于数据做出的,常常就越好。

5、错误预算的构建过程
为了基于客观数据做出决策,两个团队需要共同定义一个基于服务水平目标(SLO)的季度错误预算。
错误预算提供了一个明确的、客观的指标来决定服务在一个单独的季度中能接受多少不可靠性。
Google 的实际做法是:
  • 产品管理层定义一个SLO,确定一项服务在每个季度预计的正常运行时间。
  • 实际在线时间是通过 一个中立的第三方系统进行测算,即监控系统。
  • 这两个数字的差值就是这个季度中剩余的不可靠性预算。
  • 只要测算出的正常在线时间高于SLO,也就是说只要仍然有剩余的错误预算,就可以发布新的版本。如果频繁发布导致错误预算耗尽,那么发布就会暂停。
  • 当SLO违规导致错误预算接近耗尽时,将发布的速度减慢,或者回退到上一版本。
利用错误预算可以同时找到制定得过高的可用性目标,显示出它们所导致的灵活性和创新速度方面的问题。

二、服务质量目标
Chris Jones, John Wilkes, Niall Murphy, Cody Smith

1、服务质量术语
  • SLI,服务质量指标,比较重要的指标有请求延迟、可用性、持久性等。google云计算服务公开的可用性指标是99.95%。
  • SLO,服务质量目标,服务的某个SLI的目标值,或者目标范围。SLO的选择和公布可以帮助设立用户对服务质量的预期。如果没有一个明确的SLO,用户经常会按自己的理解设置一个服务性能的预期,容易产生过度信任或信心不足两类问题。
    • google chubby服务是一个分布式锁服务,由于chubby服务故障出现的频率太低而导致其他服务负责人开始认为chubby永远不会出故障,从而不停地将更多服务依赖于此。chubby服务实际上提供了一种安全假象,不管是多么罕见,但一旦当chubby服务发生故障后,大批依赖于它的其它服务也会变得不可用。
    • google sre的解决办法是,保证全球chubby服务达到预定义的SLO,但也不会大幅超出该SLO。每个季度,如果真实故障没有将可用性指标降低到SLO之下,SRE会刻意安排一次可控的故障——将服务停机。这样,就能很快找出那些对chubby服务的不合理依赖,然后强迫服务的负责人尽早面对这类分布式系统的天生缺陷。
  • SLA,指服务与用户之间的一个协议,描述了在达到或没有达到SLO之后的结果。这些结果可以是财务方面的,也可能是其它类型的。
    • 区别SLO和SLA的一个简单方法是问:如果SLO没有达到时,有什么后果?如果没有定义明确的后果,那么肯定是在讨论一个SLO。
    • Google最为知名的消费者产品——搜索服务是没有公开SLA的一个典型服务,也就是说其搜索服务的不可用不会为google带来某种违返合同的法律诉讼。
    • Google提供的企业产品,如Google for work,一般都是有明确的SLA协议。

2、指标在实践中的应用
一般来说,四五个具有代表性的指标对系统健康程度的评估和关注就足够了,过多过少均有负作用。
以下是几类比较常见的服务类型
  • 用户可见的服务系统,通常关心可用性、延迟以及吞吐量,即是否能正常处理请求?每个请求花费的时间是多少?多少请求可以被处理?
  • 存储类系统,通常强调延迟、可用性和数据持久性,即读写数据需要多少时间?是否可以随时访问数据?数据是否一段时间内还能被读取?
  • 大数据系统,通常关心吞吐量和端到端的延迟,即处理了多少数据?数据从输入到产出需要多少时间?
所有的系统都应该关注:正确性。是否返回了正确的回复,是否读取了正确的数据,或者是否进行了正确的数据分析操作。正确性是系统健康程度的一个重要指标,它关注的是系统内部的数据,而不是系统本身,通常不是SRE直接负责的。

将SLI落地的三个步骤:
  • 指标的收集,利用某种或几种监控系统将大部分指标都收集到服务器端,或者利用某种日志分析系统,分析日志中特定响应码或字符串所占的比例。
  • 汇总与统计分析,简单的指标数据汇总可能会带来计算错误或是掩盖服务实际的问题,因为指标的采集频率是相对固定的,而服务的并发请求处理量确是随机的。大部分的指标都应该以“分布”,而不是平均值来定义。例如针对某个延迟SLI,需要关注系统的50%、85%、95%、99%的请求延迟。
  • 指标的标准化,标准化一些常见的SLI,以避免每次都重新评估它们,例如下面
    • 汇总间隔,每1分钟汇总一次
    • 汇总范围,集群中的全部任务
    • 度量频率,每10秒一次
    • 包含哪些请求
    • 数据如何获取
    • 数据访问延迟

3、目标在实践中的应用
应该从思考用户最关心的方面入手,而非从现在能度量什么入手。用户真正关心的部分经常是度量起来很困难,甚至是不可能的,所以我们需要某种形式的近似。
如果只是从可以简单度量的数值入手,最终的SLO的作用也会有限。
因此,与其选择指标,再想出对应的目标,不如从想要的目标反向推导出具体的指标。
  • 目标的定义
    • SLO应该具体指出它们是如何被度量的,以及其有效条件;
    • 如果性能曲线也很重要的话,可以指定多个SLO;
    • 如果应用需要同时为批处理用户和在线交互式用户提供服务,可以为每种负载单独指定SLO目标;
  • 目标的选择
    • 从全局出发,而非仅以当前系统的状态,避免长期运维一个过时的系统,需要去推动架构重构;
    • 保持简单,过于复杂的SLI设计,难于理解,也容易掩盖某种系统性能的变化;
    • 避免绝对值,永远可用就是一个错误的设定,要切合实际;
    • SLO越少越好,确保每一个SLO都是必不可少的,如果开发、运维团队不能对某一个SLO达到一致,可能这个SLO就是不必要的;
    • 不要追求完美,以一个松散的目标开始,逐渐收紧,要好于一开始制定一个困难的目标却需要不断得放松;
    • 没有经过精心调校的SLO会导致浪费,让团队付出很大的代价维护一个过激的SLO,而如果SLO过于松散,又会导致产品效果很差;
  • 控制手段
    • 监控并度量系统的SLI;
    • 比较SLI和SLO,以决定是否需要执行操作;
    • 如果需要执行操作,则要决定究竟什么操作需要被执行,以满足SLO目标;
    • 执行这些操作;
  • SLO可以建立用户预期,为能让用户能拥有正确的预期,可以考虑以下策略:
    • 留出一定的安全区,对内使用更高的SLO,对外使用稍低的SLO,SLO缓冲区也可以用来进行可能影响系统属性的重构;
    • 实际SLO也不要过高,用户一般不会按合同上给出的SLO,而是按实际情况来构建服务,这在基础设备类服务上非常明显。如果服务的实际性能要比SLO宣传好太多,用户可能会逐渐依赖于现在的假象。Google会采用一些主观可控模式减少这处过度依赖,如以计划内维护来避免服务的过于可用,也会采取对一些请求限速,或限制系统在低负载下也不会速度过快。

2、协议在实践中的应用
起草一份SLA需要业务部门和法务部门选择合适的后果条款。在用户宣传方面最好保持保守,因为受众越广,修改或删除一个不适用或很困难达到的SLA就越困难。
Google云计算服务对外公开的服务可用性SLA是99.95%,即服务的年停机时间最多为4.38小时。

三、减少琐事
Vivek Rau

SRE需要把更多的时间花费在长期项目研发上,而非日常琐事中。
1、“琐事”的定义
  • 琐事不是什么?
    • 一些行政管理类的杂务是必须做的,不该被归为琐事;
    • 团队会议、目标的建立和评估、每周总结以及人力资源、任务绩效管理等都不算作琐事;
    • 脏活累活通常具有长期价值,不能算作琐事,例如为服务清理警报规则或降低噪声率;
  • 琐事是什么?
    • 琐事是运维服务中手动性、重复性的,可以被自动化的,战术性,没有持久价值的工作。
    • 琐事与服务呈线性关系的增长,每件琐事都具有以下一个或多个属性:
      • 手动性,例如手动运行脚本以便自动执行一些任务,具体运行脚本所花费的手动的时间应该被认为是琐事;
      • 重复性的,那些不停地、反复做的工作应该被认为是琐事,但如果你在解决一个新出现的问题或者寻找一种新的解决办法,不算作琐事;
      • 可以被自动化的,如果可以让计算机和人一样能够很好地完成某个任务,或者通过某种设计变更来彻底消除对某项任务的需求,这项任务就是琐事。但如果在任务处理中的主观判断是必需的,那么很大程度上这项任务不属于琐事。
      • 战术性的,琐事是突然出现的、应对式的工作,而非策略驱动和主动安排的,处理紧急警报是琐事,我们必须努力减少它。
      • 没有持久价值,如果你在完成某项任务后,服务状态没有改变,这项任务就很可能是琐事。如果这项任务给服务带来永久性的改进,它就不是琐事。
      • 与服务同步线性增长,如果在工作中所涉及的任务与服务的大小、流量或用户数量呈线性增长关系,那这项任务可能属于琐事。一个良好管理和设计的服务应该至少可以应对一个数量级的增长,而不需要除某些一次性工作(如增加计算资源)之外的额外工作。

2、“琐事”越少越好
  • SRE的一个公开目标是保持每个SRE的工作时间中,“琐事”的比例低于50%。琐事通常有一定集中性,但按全年或某个季度来说,需要将琐事”平均的比例控制在50%以下。
  • SRE至少花50%的时间在工程项目上,以减少未来的琐事或增加服务功能,增加服务功能包括提高可靠性、性能,或利用率,同时也会进一步消除琐事。
  • 50%这个目标如果不加以控制,琐事会变得越来越多,以至于迅速占据我们每个人100%的时间。Google会明文禁止SRE组织或其中任何小团队退化为专门从事运维工作的组织。
  • 对工程工作的关注,使SRE可以在服务规模扩大的同时减少人数,并能更有效得管理服务。

3、什么算作“工程工作”
  • 工程工作是一种新颖的、本质上需要主观判断的工作。
  • 工程工作是符合长期战略的,会对你的服务进行长久性改善的工作。
  • 工程工作通常是有创新性和创造性的,着重通过设计来解决问题,解决方案越通用越好。
  • 工程工作有助于使用该团队或是整个组织在维持同等人员配备的情况下,接手更大或者更多的服务。
  • 典型的SRE活动有以下几类:
    • 软件工程,写代码以及所有其它相关的设计和文档工作,例如编写自动化脚本,创造工具或框架,增加可扩展性和可靠性的服务功能,或修改基础设施代码以使其更稳健。
    • 系统工程,配置生产系统、修改现存配置,或者用一种通过一次性工作产生持久的改进的方法来书写系统文档。例如,监控的部署和更新、负载均衡的配置、服务器配置、操作系统的参数调整和负载均衡器的部署。系统工程还包括与研发团队进行的架构、设计和生产环境方面的咨询工作。
    • 琐事,那些运维相关的,重复性的、手工的劳动。
    • 流程负担,与运维服务不直接相关的行政工作,如招聘、团队会议、工作任务管理、工作总结、同行评价和自我评价以及培训课程等。

4、“琐事”繁多的负面影响
琐事多是一些低风险低压力的活动,在数量上不是特别多的时候,这些已知的和重复性的工作有一种让人平静的功效,完成这些工作可以带来一种满足感和快速胜利感,以致于有些员工喜欢做这种类型的工作。但是一旦琐事的数量变多,就会有害了,以下是几个比较突出的害处:
  • 职业停滞,如果花在工程项目上的时间太少,你的职业发展会变慢,甚至停滞。
    • Google会奖励做那些脏活累活的人,但是仅仅是该工作是不可避免,并有巨大的正面影响的时候才会这样做;
    • 没有人可以通过不停地做脏活累活满足自己的职业发展;
  • 士气低落,过多的琐事会导致过度劳累、厌倦和不满。
  • 造成误解,SRE的自身定位是一个工程组织,如果个人或团队过度参与琐事,会破坏这种角色认同,造成误解。
  • 进展缓慢,琐事过多会导致团队生产力下降,如果SRE团队忙于为手工操作和导出数据救火,新功能的发布就会变慢。
  • 开创糟糕的先例,如果SRE过于愿意承担琐事,研发同事、测试同事就更倾向于加入更多的琐事,有时候甚至将本该由自己承担的工作转给SRE来承担,例如新系统研发中的部分软件安装、配置、调试工作。
  • 促进摩擦产生,即使你个人对琐事没有怨言,你的队友可能会很不开心。如果团队中引入了太多的琐事,可能会促使团队里最好的工程师开始寻找其他地方提供的更有价值的工作。
  • 违反承诺,为了从事项目工程工作而入职的新员工以及从内部转入SRE的老员工会有被欺骗的感觉,影响到公司、团队的士气。

如果我们都致力于每一周通过工程工作消除一点琐事,就可以持续性地整顿服务。我们就可以将更多的力量投入到扩大服务规模的工程工作上去,或者昌进行下一代的服务的架构设计,又或者是建立一套跨SRE使用的工具链。
多创新,少干琐事!

四、分布式系统的监控
Rob Ewaschuk

Google 的SRE团队在构建监控系统和报警系统方面遵循的一些核心思想和最佳实践。
健康的监控和警报系统应该是非常简单、易于理解的。紧急警报应该关注于现象、针对原因的一些启发性分析应该作为调试过程的补充,而不应该进行报警。E-mail警报的价值通常很低,很容易变成噪声。我们应该倾向于构建一个良好的监控台页面,直接显示所有的非紧急的异常情况。
从长远来看,要建立一个成功的on-call轮值体系,以及构建一个稳定的产品需要选择那些正在发生和即将发生的问题来进行报警,设置一个可以实际达到的合理目标,保证监控系统可以支持快速的问题定位与检测。

1、监控相关的术语
  • 监控(monitoring),收集、处理、汇总并且显示某个系统的实时量化数据;
  • 白盒监控(white-box monitoring),依靠系统内部暴露的一些性能指标进行监控,包括使用日志分析、java虚拟机提供的监控接口或者一个列出内部统计数据的HTTP接口进行监控;
  • 黑盒监控(black-box monitoring),通过测试某种外部用户可见的系统行为进行监控,如对web api返回响应的监控;
  • 监控台页面(dashboard)
  • 警报(alert),目标对象是某个人发向某个系统地址的一个通知,目的地可以包括工单系统(由监控预警自动创建工单)、email警报、短信警报、电话警报;
  • 根源问题(root cause),指系统中的某种缺陷,这个缺陷如果被修复就可以保证这种问题不会再以同样的方式发生,每一个根源问题都需要被修复;
  • 节点或机器(node/machine);
  • 推送(push),关于某个服务正在运行的软件或者其配置文件的任何改动;

2、为什么要监控
  • 分析长期趋势
  • 跨时间范围的比较,或者是观察实验组与控制组之间的区别
  • 报警
  • 构建监控台页面,监控台页面应该可以回答有关服务的一些基本问题,通常会包括常见的4个“黄金指标”
  • 临时性的回溯分析,即在线调试,例如我们的请求延迟刚刚大幅增加了,有没有其他的现象同时发生?
监控与报警可以让一个系统在发生故障时主动通知我们,或者能够告诉我们即将发生什么。不应该仅仅因为“某东西看起来有点问题”就发出警报。
高效的警报系统应该提供足够的信息,并且误报率非常低。

3、四个黄金指标
如果我们只能监控用户可见系统的4个指标,那么就应该监控延迟、流量、错误和饱和度这4个。
  • 延迟
  • 流量,不仅仅指网络流量,而是泛指使用系统中的某个高层次的指标针对系统负载需求所进行的度量,例如WEB服务器的每秒HTTP请求的处理数量,磁盘I/O读写数量,网络吞吐速率,redis的每秒读写操作数量;
  • 错误
  • 饱和度,评价服务容量有多“满”,通常是系统中目前最为受限的某种资源的某个具体指标的度量;
如果我们度量所有这4个黄金指标,同时在某个指标出现故障时发出警报,能做到这些,服务的监控就差不多了。

4、度量指标时采用合适的精度
系统的不同部分应该以不同的精度进行度量。
服务质量目标不同的系统或应用,应该以不同的精度进行度量。
一些容易发生的监控指标采集精度设置问题:
  • 观察1分钟内的CPU平均负载可能会错失某种较长时间内的CPU峰值现象;
  • 对于一个年停机时间小于9小时(可用性99.9%)的WEB服务来说,每分钟检测1次或2次的监控频率可能过于频繁;
  • 对目标可用率为99.9%的某个服务,每分钟检查一次硬盘剩余空间可能也是没必要的;

如果我们的监控目标需要高精度的监控数据,如每秒采集一次,却不需要极低的延迟,则可以通过一些内部采样、外部汇总的方式降低成本。
例如:
  • 将当前CPU利用率按秒记录;
  • 按5%粒度分组,将对应的CPU利用率计数+1;
  • 将这些值每分钟汇总一次;
这种方式使我们可以观测到短暂的CPU热点,但又不需要为此付出高额成本进行收集和存储高精度数据。

5、简化到不能再简化
Google的监控系统设计原则就是追求简化:
  • 那些最能反映真实故障的规则应该越简单越好,可预测性强,非常可靠;
  • 那些不常用的数据收集、汇总,以及警报配置应该定时删除(例如设定一个标准,在一个季度里没有用到一次的报警规则即将其删除);
  • 收集到了信息,但是没有暴露给任何监控台,也没有被任何警报规则使用的,应该定时删除;

6、为监控系统添加新规则时请回答下列问题
  • 该规则是否能检测到一个目前检测不到的、紧急的、有操作性的,并且即将发生或者已经发生的用户可见故障?
    • 零冗余(N+0)的情况也应该算是即将发生的故障的情况;
    • 接近满载的情况同样也应该算是即将发生的故障的情况;
  • 是否可以忽略这条警报?什么情况可能会导致用户忽略这条警报,如何避免?
  • 这条警报是否确实显示了用户正在受到影响?是否存在用户没有受到影响也可以触发这条规则的情况,原因是什么,如何避免?
  • 收到警报后,是否要进行某个操作?是否需要立即执行该操作,还是可以等到第二天早上再进行?该操作是否可以被安全地自动化?该操作的效果是长期的,还是短期的?
  • 是否也会有期他人收到相关的紧急警报,这些紧急警报是否是不必要的?

7、应对紧急警报的一些重要理念
  • 每当收到紧急警报时,应该立即需要进行某种操作,每天只能进入紧急状态几次,太多就会导致“狼来了”效应;
  • 每个紧急警报都应该是可以具体操作的;
  • 每个紧急警报的回复都应该需要某种智力分析过程,如果某个紧急警报只是需要一个固定的机械动作,那么它就不应该成为紧急警报;
  • 每个紧急警报都应该是关于某个新问题的,不应该彼此重叠;


五、Google的自动化系统的演进
Niall Murphy、John Looney、Michael Kacirek

对于SRE而言,自动化是一种力量倍增器,但不是万能药。对力量的倍增并不能改变力量用在哪的准确性。草率地进行自动化可能在解决问题的同时产生出其他问题。
虽然我们认为在大多数情况下以软件为基础的自动化是优于手动操作的,但是比这两个选择更好的方案是一个不需要这些的系统设计——一个自治的系统。
自动化的价值不仅来源于它所做的事情,还包括对其的明智应用。

1、运维自动化的价值
  • 一致性,管理成百上千、成千上万的机器时,没有几个人能像机器一样永远保持一致,这种不可避免的不一致性会导致错误、疏漏、数据质量的问题和可靠性问题。在这个范畴内——一致性地执行范围明确、步骤已知的程序——是自动化的首要价值。
  • 平台性,通过正确地设计和实现,自动化的系统可以提供一个可以扩展的、广泛适用的,甚至可能带来额外收益的平台。
    • 一个平台同时也将错误集中化了,在代码中修复某个运维任务中的错误,可以保证该错误被永远修复;
    • 一个平台更容易地被扩展,从而执行额外的任务,可以更持续、更频繁地运行任务;
    • 帮助你发现流程中以前所不知道的细节,工程师可以在构建自动化系统的过程中更深刻地理解现有流程;
  • 修复速度更快,采用自动化系统解决系统中的常见故障可以带来额外的好处,如果自动化系统始终成功运行,那么就可以降低一些常见故障的平均修复时间。
  • 行动速度更快,人类通常不能像机器一样快速反应,Google拥有大量的自动化系统,在很多情况下,没有自动化参与的技术支持服务,这些服务就不能长久运行,因为它们早就超越了人工操作所能管理的门槛。
  • 节省时间
对于真正的大型服务来说,一致性、快速性和可靠性这些因素主导了大多数有关自动化的权衡的讨论。

2、运维自动化的应用案例
在运维行业中,自动化这个术语一般用来指代通过编写代码来解决各种各样的问题。自动化工具相当于是“元软件",即操作其它软件的软件。
运维自动化有许多的用例,如:
  • 创建某个用户帐户;
  • 某个服务在某个集群中的上线和下线过程;
  • 软件或硬件安装的准备和退役过程;
  • 新软件版本的发布;
  • 运行时配置的更改;
  • 一种特殊情况的运行时配置变更:依赖关系的更改;
这个列表基本上可以无限扩展。

3、Google SRE自动化案例——让自己脱离工作,自动化所有的东西
很长一段时间内,Google的广告产品将数据存储于一个mysql数据库中,需要很高的可靠性。
2005年到2008年间,一个SRE团队将标准副本替换流程的常规工作中最糟糕的部分自动化掉了,但没有将全部工作自动化。随着是常工作变得越来越容易,SRE团队开始考虑将mysql迁移到Google的集群调度系统Borg之下。这样考虑的理由是:
  • 希望彻底消除对物理机/数据库副本的维护,由Borg自动安装新任务或重启出问题的任务;
  • 将多个Mysql实例安装在同一个物理机上,利用容器化可以更好地利用计算机资源;
  • 手动故障转移将消耗大量的人力时间,对产品可用性会造成冲击;
  • 为了满足错误预算要求,每个故障转移的停机时间要求小于30s,继续优化依赖人为操作的流程是达不到这一目标的;
2009年,Google 广告SRE完成了自动故障切换后台程序,mysql on Borg最终变成了现实。
SRE团队在无聊的运维任务上花费的时间下降了95%,整 个故障转移是自动化的,所以单个数据库任务中断不再给任何人发出紧急警报。
这一新的自动化的好处是,SRE有更多的空闲时间花在改进基础设施的其它部分上,节省的时间越来越多,导致广告数据库的总运维成本下降了95%。

4、Google SRE自动化案例——将自动化应用到集群上线中
集群上线自动化进化遵循这样一个路径:
  • 操作人员触发手动操作(无自动化);
  • 操作人员编写,系统特定的自动化;
  • 外部维护的通用自动化;
  • 内部维护,系统特定的自动化;
  • 不需要人为干预的自治系统。

一个复杂的东西一定是诞生于简单初始环境的不断演变。

Google在这一过程中踩了很多坑,早期的自动化关注于加速集群交付,往往依靠”有创意“的使用一些脚本工具来应对繁琐的包分发和服务初始化问题。采用这一策略一开始很成功,但是这些格式自由的脚本逐渐堆积成了技术债务。我们用来配置集群的、有创造性的——但是脆弱的——shell脚本既无法适应需要修改该脚本的人的数量增加,也不能适应需要构建的集群的大量组合形式。
所有的可执行的脚本都执行过一遍了,但是:
  • 是否所有服务的依赖关系都可用,并且正确地配置了?
  • 所有的配置和包都与其他部署一致吗?
  • 团队是否能够确认配置中的每个例外都是合理的?

Google的解决办法一:Prodtest——生产测试
对Python单元测试框架进行了扩展,使其可以用来对生产环境实际服务进行单元测试。这些单元测试有依赖关系,允许进行链条式测试,一个测试中出现的故障可以很快中止整个测试。下图是DNS服务的测试用例。每当一个团队遇到因另一个团队意外错误配置而导致的延迟时,可以提交一个bug来扩展Prodtest。
Google的解决办法二幂等地解决不一致情况
注:一个失败测试的后果 仅仅是多运行一个修复程序。要求修复程序尽可能得具备幂等性。


Google的终极解决办法:Borg——仓库规模计算机的诞生
  • Google的集群最初:
    • 就是一个小型网络部署规模,有特定用途和各种异构配置的很多机柜服务器。
    • 工程师将登录到一些管理主机上执行管理任务,关键的数据和配置文件都 保存在这些主机上。
    • 当时只有一个IDC托管供应商,大多数主机的命名逻辑隐含地假定了位置信息。
  • 随着生产环境的增长,开始使用多个集群:
    • 多个域(集群名称)也变得有必要了。
    • 需要一个文件来描述每个机器做了什么,以一些松散命名策略将机器编组。
    • 使用并行化的SSH工具,批量管理主机和服务。
  • 运维自动化获得快速发展阶段:
    • 最初的自动化包括使用简单的python脚本进行服务管理、日志消息解析等;
    • 自动化最终成长为使用一个数据库来跟踪机器状态,并且采用了更先进的监控工具;
    • 随着自动化系统的成长,可以自动管理机器的大部分生命周期,当机器坏了,移除服务,送去修理 并且在它们修好后恢复配置等;
  • 进入Borg阶段:
    • 前面的自动化工作是有用的,但是限制非常多,因为该系统的抽象与物理机紧密相关;
    • Borg将一系列的机器看作是受管理的海量资源,把集群管理变成了一个可以通过API调度管理的中央协调主体;
    • Borg能让机器调度各种运维管理任务,包括机器的生命周期管理、报修、部署或迁移应用,成千上万的机器加入系统或者出现问题,被修复,这一切都不需要SRE的任何操作,因为一旦计算机的增长超过了一定规模,它必须是自我修复的,根据统计学来说,每秒它都会发生大量故障;
    • SRE们通过最初的自动化努力给自己争取了足够的时间,通过相关的数据分布、API、集中式架构以及经典的分布式软件系统研发进入了基础设备管理领域,把集群管理成功得转为了自治系统

5、大规模自动化系统易引发大规模故障
Google目前有自建的十几个大型数据中心,还有几十或上百个租用的第三方托管设施内的机器。这些第三方设备中的机器大多是用于用户接入或CDN缓存用途的。
在任何一个时间点,都会有很多机架被安装或退役,这些过程大部分是自动化的。Google这种设备运行规模,基本上都是按机架为单位进行上、下架管理的。
其中”拆除“步骤中包括覆写机架上所有机器的磁盘,同时会有另一个独立的系统去验证前面的操作是否执行成功。

某一天,在某个特定机架退役的过程中自动化系统出现了问题,只有磁盘擦除步骤成功完成了,校验系统执行失败了,于是SRE重启了设备清退过程以调试为什么会失败。在这次操作中,当程序试图给磁盘清除系统发送待清除的机器列表时,代码得出的机器列表是空的(正确的答案)。不幸的是,空列表有着特殊含义,它被解释为”所有“。于是这个第三方托管设施内所有的机架中所有的设备都被送去进行磁盘清除了!

几分钟内,高效的磁盘擦除程序完成了这项工作任务。事实上由于良好的容量规划,对外部的唯一影响就是会有轻微的延迟增加。
接下来,SRE们花了两天时间重装受影响的机架上的机器,然后又花了几周的时间进行代码审计,在自动化系统中添加了更多的合理性检查,包括速率限制,以及使整个退役流程具有幂等性。

六、发布工程
Dinah McNutt

发布工程专注于构建和交付软件。
发布工程师通常需要对源代码管理、编译器、构建配置语言、自动化构建工具、包管理器和安装器等非常了解。

为保障服务可靠运行,需要可靠的发布流程。SRE需要保证二进制文件和配置文件是以一种可以重现的、自动化的方式构建出来的。 这样每一次发布才是可以重复的。

1、发布工程哲学
  • 自服务模型,发布工程师开发工具,制定最佳实践,以便让产品研发团队可以自己掌控和执行自己的发布流程。为了应对大规模扩张,每个团队必须能够自给自足。
    • Google 有几千个工程师、几百个产品,但仍然能够以很快的速度发布新产品,原因是每个团队都做到了自服务;
    • 发布过程可以自动化到基本不需要工程师干预,很多项目是利用自动构建工具和部署工具自动构建、自动发布的;
    • 发布过程 是真正的自动化的,运维工程师仅在发生问题时才会进行干预;
  • 追求速度,面向用户的软件组件重新构建非常频繁,目标是让用户可见的功能尽早上线,同时频繁的发布可以使得每个版本间的变更减少,降低调试、测试的复杂度。
    • 在Google有的团队每小时构建一次,然后在所有可用的版本中选择某个版本进行发布;
    • 还有的团队采用一种“测试通过即发布”的发布模型;
  • 密闭性,构建工具必须确保一致性和可重复性,如果两个工程师试图在两台机器上基于同一个源代码版本构建同一个产品,构建结果应该是相同的。
    • 构建过程都是密闭的,意味着它们不受构建机器上安装的第三方类库或其他软件工具所影响;
    • 编译过程是自包含的,使用指定版本的构建工具,同时使用指定版本的依赖库,不依赖于编译环境之外的其他服务。
    • 构建工具自身也是放置在与被构建的程序同一个源代码仓库之中的,如果要对上个月构建的某个项目进行版本回退,仍会使用当时的编译器版本。
  • 强调策略和流程,多层安全和访问控制机制可以确保在发布过程中只有指定的人才能执行指定的操作。需要重点关注的操作有如下几项。
    • 批准源代码改动;
    • 指定发布流程中需要执行的具体动作;
    • 创建新的发布版本;
    • 批准初始的集成请求(以某个源代码仓库版本为基础的构建请求),以及后续的cherry picking请求;
    • 实际部署某个发布版本;
    • 修改某个项目的构建配置文件;
注:摘樱桃,Google按照之前的源代码版本,加入一些后来提交的改动来构建新的发布来解决某个问题,这种方式被称为“摘樱桃”。

自动化发布系统可以提供每个发布中包含的所有改动的报告,与其它的构建结果一起归档。SRE可以了解每个新发布中包含的具体改动,在发布出现问题时可以更快地进行在线调试。

2、持续构建与部署
Google开发了一个自动化的发布系统:Rapid。该系统利用一系列Google内部技术执行可扩展的、密闭的、以及可靠的发布流程。
  • 构建,Blaze是Google的构建工具,支持多编程语言
    • 工程师利用Blaze定义构建目标,同时给每个目标指定依赖关系,当进行构建时,Blaze会自动构建目标的全部依赖;
    • 在Rapid的项目配置文件中定义构建目标,如二进制文件以及对应的测试等,会由Rapid传递给Blaze;
    • 所有二进制文件都支持用一个命令显示自身的构建时间、构建源码版本,以及构建标识符,这样就很容易地将一个二进制文件与构建过程对应起来;
  • 分支,所有的代码都默认提交到主分支上(mainline),但是大部分的项目都不会直接从主分支上进行发布。
    • 一般会基于主分支的某一个版本创建新分支,新分支的内容永远不会再合并入主分支;
    • Bug修复先提交到主分支,再cherry picking到发布分支上;
  • 测试,Google在一个项目发布上线的过程中有一套完整的测试流程规范要注。
    • 有一个持续测试系统会在每个主分支改动提交之后运行单元测试;
    • 在发布过程中,会使用该发布分支重新运行全部单元测试,同时为测试结果创建审核记录;
    • 对于cherry picking发布,在发布分支上可能会包含主分支上不存在的一个代码版本,必须确保在发布分支上全部测试通过;
    • 使用一套独立的测试环境来在打包好的构建结果上运行一些系统级别测试,这些测试可以从Rapid网站上手工启动;
  • 打包,MPM(Midas Package Manager)是Google的打包与分发工具。
    • MPM基于Blaze规则列出的构建结果和权限信息构建MPM包;
    • 每个包有固定的名称,记录构建结果的哈希值,并且会加入签名以确保真实完整性;
    • MPM支持给某个版本的包打标签,同时Rapid也会加入一个构建ID标签;
    • 可以给MPM包打位置标签,标记该MPM包在整个发布过程中的位置(如dev, canary或production);

3、Rapid系统
下图展示了Rapid系统中的主要组件。
  • Rapid是用Blueprint文件配置的,Blueprint是一种利用Google内部配置语言写成的,用来定义构建目标和测试目标、部署规则,以及一些管理用信息(如项目负责人信息);
  • 基于角色的访问控制列表可以决定谁能执行哪些动作;
  • 每个Rapid项目都有一些工作流,定义了发布流程中的具体动作,工作流可以线性或并发执行,某个工作流也可以启动另外一个工作流;
  • Rapid将工作请求分发给运行在Borg系统上的生产服务器,具备同时处理几千个发布请求的能力;

典型的Rapid发布流程如下:
  • Rapid使用集成版本号(通常自动从持续测试系统获取)创建新的发布分支;
  • Rapid利用Blaze编译所有的二进制文件,同时执行所有的单元测试,以上两个过程是并发的,编译和测试分别有各自相对独立的环境;
  • 构建结果随后可以用来运行系统级集成测试,同时进行测试部署,典型的测试部署过程是在系统测试完成之后,在生产环境中启动一系列的Borg任务;
  • 每一步的结果都有日志记录,另外产生一份与上次发布对比包含的所有新的改动列表的报告;
  • Rapid可以管理发布分支与cherry picking,每个具体的cherry picking请求可以被单独批准和拒绝;

4、部署
Rapid经常被用来直接驱动简单的部署流程,它可以根据Blueprint文件定义的部署规则,利用具体的任务执行器(executor)来用新的MPM包更新Borg任务。

Google SRE开发的一个发布自动化框架——Sisyphus,用来执行更为复杂的部署任务。

  • 一个发布(rollout)是由一个或多个任务组成的一个逻辑单元;
  • Sisyphus提供了一系列可扩展的python类,以支持任意部署流程;
  • Sisyphus还提供一个监控台,用以详细控制每个发布的执行,以及监控发布流程;
  • 在一次典型的集成流程中,Rapid在某个Sisyphus系统中创建一个新的发布,传入指定的MPM包的build标签,Sisyphus据此执行发布逻辑进行部署;
  • Sisyphus可以支持简单的发布流程,也可以支持复杂的发布流程,可以立即更新所有的相关任务,也可以在几小时的周期内一个接一个地更新集群版本;
  • 部署流程的选择是与应用的风险随能力相结合的:
    • 开发环境或预生产环境,可能会每小时构建一次,同时在所有测试通过后立即自动发布更新;
    • 对于大型面向用户的服务,可能会先更新一个集群,观察和验证后再以指数速度更新其他全部集群;
    • 对敏感的基础设施服务,可能会将发布扩展到几天内完成,根据这些基础实例所在的地理位置交替进行;

5、配置管理
Google使用多种配置管理模型,但所有这些模型都需要将配置文件存放于代码仓库中,同时进行严格的代码评审。
  • 使用主分支版本配置文件,这是配置Borg服务的第一个方法,通过修改主分支上的配置文件,同时对所有的发布分支生效。这个模型的特点更像是一种配置文件的模板,会应用到所有的发布分支上去,但需要经过更新才能应用这些变更。
  • 将配置文件与二进制文件打包在同一个MPM包中,类似于一个war包在内部直接使用正确的信息进行配置文件的设置,这个模型在灵活性上受限,但简化了部署;
  • 将配置文件打包成MPM配置文件包,利用编译系统和打包系统来发布配置文件,这样可以反复发布多次配置文件,而不需要每次都对二进制文件做重新构建;
  • 从外部存储服务中读取配置文件,某些项目的配置文件需要经常改变,或者动态改变,Google把这些配置文件存放在Chubby、Bigtable或者基于源代码仓库的文件系统中。
项目负责人在颁发和管理配置文件时有多种选择,可以按需决定究竟哪种最合适该服务。

当采用合适的工具,合理的自动化方式,以及合理的政策时,开发团队和SRE都无须担心如何发布软件。发布过程可以像按一个按钮那么简单。

项目团队应该在开发流程开始时就留出一定资源进行发布工程工作,尽早采用最佳实践和最佳流程可以降低成本,以免未来重新改动这些系统。


七、简单化
Max Luebbe

软件的简单性是可靠性的前提条件。当我们考虑如何简化一个给定的任务的每一步时,我们并不是在偷懒,相反我们是在明确实际上要完成的任务是什么,以及如何更容易地做到。
我们对新功能说“不”的时候,不是在限制创新,是在保持环境整洁、统一,以免分心。
这样我们可以持续关注创新,并且可以进行真正的工程工作。

1、系统的稳定性与灵活性
SRE通过创造流程、实践以及工具,来提高软件的可靠性。同时SRE需要最小化这些工作对于开发人员灵活性造成的影响。

事实上,SRE的经验表明,可靠的流程会提高研发的灵活性,快速、可靠的产品发布使得生产系统中的变化显而易见。

2、乏味是一种美德
生产环境中的意外是SRE最大的敌人,我们希望工具或程序按设计执行,可以预见性地完成商业目标,“乏味”是非常下面的态度,不要追求自发性和有趣的程序。

需要特别关注必要复杂度和意外复杂度之间的区别:
  • 必要复杂度,是一个给定的情况所固有的复杂度,不能从该问题的定义中移除;
  • 意外复杂度,是不固定的,可以通过工程上的努力解决,而非软件层面;

为了最小化意外复杂度,SRE团队应该:
  • 在他们所负责的系统中引入意外复杂度时,及时提出抗议;
  • 不断地努力消除正在接手的和已经负责运维的系统的复杂度;

3、删除已经无用的代码
定期删除无用代码,并且在各级测试中增加代码膨胀检测。
添加到项目中的每行代码都可能引入新的缺陷和错误。

4、最小化API
书写一个明确的、最小的API是管理软件系统管理简单性必要的部分。我们向API消费者提供的方法和参数越少,这些API就越容易理解,我们就能用更多的精力去尽可能地完善这些方法。
一个很小的,很简单的API通常是一个对问题深刻理解的标志。

5、模块化
  • 对于分布式系统,对系统中某个部分进行隔离式的变更能力对创建一个可以运维的系统来说是非常必要的。
    • 在二进制文件之间或者二进制文件与配置文件之间推行松耦合,是一种同时提高开发人员的灵活性和系统的稳定性的简化模式;
  • 通过将API版本化把模块化的概念引入API的变更管理,同时提供多个版本的API,允许开发人员继续使用它们的系统所依赖的版本,然后以更安全和深思熟虑的方法升级到新的版本。
  • 随着系统复杂性的增加,API与二进制文件之间的责任分离也变得越来越重要,一个设计良好的分布式系统是由一系列合作者组成的,每一个合作者都具有明确的,良好定义的范围。
  • 模块化的概念同样适用于数据格式,Google的Protobuf的一个主要优势和设计目标就是创建一个同时向后和向前兼容的传输格式。

6、发布的简单化
  • 简单的发布流程总的来说要比复杂的发布流程好。
  • 测试和理解单一变化的影响要比同时应对一系列变化更加容易。
  • 如果同时发布100个不相关的系统更改,而系统性能变差了,我们需要花费大量时间和努力来定们问题。
  • 如果发布是按更小的批次进行的,我们就可以更有信心地进行更快的发布。
  • 通过每次进展一点,同时考虑每次改变对系统的改善和退化来寻找最佳方案。


0 0