SRE:Google运维解密
>> 有统计显示,一个软件系统的40%~90% 的花销其实是花在开发建设完成之后不断维护过程中的。
>> 我们认为如果软件工程职业主要专注于设计和构建软件系统,那么应该有另外一种职业专注于整个软件系统的生命周期管理。从其设计一直到部署,历经不断改进,最后顺利退役。这样一种职业必须具备非常广泛的技能,但是和其他职业的专注点都不同。Google 将这个职位称为站点可靠性工程师(SRE,Site Reliability Engineering)。
>> SRE 使用计算机科学和软件工程手段来设计和研发大型、分布式计算机软件系统。
>> 理想情况下,同时推进这些组件在多个项目中复用。还有的时候,我们的任务是想出各种各样的办法用现有组件解决新的问题。
>> 其次,SRE 的关注焦点在于可靠性。
>> 因为可靠性[2]是如此重要,因此SRE 专注于对其负责的软件系统架构设计、运维流程的不断优化,让这些大型软件系统运行得更可靠,扩展性更好,能更有效地利用资源。
>> SRE并不是无止境地追求完美:当一个系统已经 “足够可靠”的时候,SRE 通常将精力转而投入到研发新的功能和创造新的产品中。
>> SRE 的主要工作是运维在分布式集群管理系统上运行的具体业务服务(service)。
>> 虽然在应用系统运营维护的过程中有数不清的重要环节需要关注,我们最关注的是“可靠性”这一点也不奇怪。
>> 本书第4部分着重介绍了 SRE 团队如何进行内部培训、如何加强内部沟通等最佳实践,很多都可以直接拿来应用。
>> 团队文化就是从一切经历中不断学习,包括来自那些我们最意想不到的地方的经历。”
>> Margaret 曾经说过:“无论对一个软件系统运行原理掌握得多么彻底,也不能阻止人犯意外错误。”
>> 希望读者以史为鉴,只有靠着对细节的不懈关注,做好充足的灾难预案和准备工作,时刻警惕着,不放过一切机会去避免灾难发生。这就是SRE 最重要的理念!
>> 我们推荐从第2章和第3章开始。这两章描述了Google的生产运行环境,以及SRE 是如何系统化认知与量化“风险”的(毕竟 “风险”是SRE最关注的要点)。
>> 本书逻辑上分为以下几个部分:理念性介绍(第Ⅱ部分)、最佳实践(第Ⅲ部分)和管理经验(第Ⅳ部分)。
>> 我们故意与行业内流行的词语 DevOps进行区分。虽然我们认同基础设施即代码的理念,但我们主要关注的是可靠性。同时,我们也更倾向于将运维的需要直接消除
第1章 介绍
>> 不能将碰运气当成战略。——SRE俗语
系统管理员模式
>> 1.直接成本。
>> 随着系统复杂度的增加,部署规模的扩大,团队的大小基本与系统负载成线性相关,共同增长。
>> 2.间接成本。
>> 从本质上来说,由于研发团队和运维团队背景各异,技术能力与工具使用习惯上差距巨大,工作目标也截然不同。两个团队对产品的可靠程度要求理解不同,具体执行中对某项操作的危险程度评估与可能的技术防范措施也有截然不同的理解。
>> 传统的研发团队和运维团队分歧的焦点主要在软件新版本、新配置的变更的发布速度上。研发部门最关注的是如何能够更快速地构建和发布新功能。运维部门更关注的是如何能在他们值班期间避免发生故障。
>> 开发团队宣称他们不再进行大规模的程序更新,而是逐渐转为功能开关调整、增量更新,以及补丁化。采用这些名词的唯一目的,就是为了绕过运维部门设立的各种流程,从而能更快地上线新功能。
Google的解决之道:SRE
>> SRE团队通过雇佣软件工程师,创造软件系统来维护系统运行以替代传统模型中的人工操作。
>> SRE就是让软件工程师来设计一个新型运维团队的结果。
>> 目前来看,UNIX 系统内部细节和1~3层网络知识是Google最看重的两类额外的技术能力。
>> 我们很快发现SRE团队成员具有如下特点:(a)对重复性、手工性的操作有天然的排斥感。(b)有足够的技术能力快速开发出软件系统以替代手工操作。
>> 这些SRE倾向于通过设计、构建自动化工具来取代人工操作。
>> SRE模型成功的关键在于对工程的关注。如果没有持续的、工程化的解决方案,运维的压力就会不断增加,团队也就需要更多的人来完成工作。
>> 为了避免这一点,负责运维这个服务的团队必须有足够的时间编程,否则他们就会被运维工作所淹没。因此,Google为整个SRE团队所做的所有传统运维工作设立了一个50%的上限值。传统运维工作包括:工单处理、手工操作等
>> 随着时间推移,SRE团队应该倾向于将基本的运维工作全部消除,全力投入在研发任务上。因为整个系统应该可以自主运行,可以自动修复问题。我们的终极目标是推动整个系统趋向于无人化运行,而不仅仅是自动化某些人工流程。
>> Google的经验法则是,SRE团队必须将50%的精力花在真实的开发工作上。
>> 我们是如何确保每个团队都是这样做的呢?
>> 首先,我们必须不断地度量每个团队的工作时间分配。
>> 对在开发工作上投入时间不够的团队进行调整。通常,管理层会要求该团队将一些常见的运维工作交还给产品研发部门操作,或者从产品研发部门抽调人力参与团队轮值值班工作。
>> 由于SRE在调整Google系统的过程中常常直接参与开发、修改代码,SRE文化在公司内部基本代表了一种快速、创新、拥抱变化的文化。
>> 整个产品部门的人员都有机会学习和参与大规模运维部署活动,从中获得平时难以获得的宝贵知识。普通的开发人员有多少机会能将自己的程序同时跑在100万个CPU的分布式系统上呢?
>> 我们可以认为DevOps是SRE核心理念的普适版,可以用于更广范围内的组织结构、管理结构和人员安排。同时,SRE是DevOps模型在Google的具体实践,带有一些特别的扩展。
SRE方法论
>> 一般来说,SRE团队要承担以下几类职责:可用性改进,延迟优化,性能优化,效率优化,变更管理,监控,紧急事务处理以及容量规划与管理。
>> 下面这几小节具体描述了Google SRE的几个核心方法论。
>> 确保长期关注研发工作
>> 在实践中,SRE管理人员应该经常度量团队成员的时间分配,如果有必要的话,采取一些暂时性措施将过多的运维压力转移回开发团队处理。例如:将生产环境中发现的Bug和产生的工单转给研发管理人员去分配,或者将开发团队成员加入到轮值on-call体系中共同承担轮值压力等。
>> 只有整个产品部门都认同这个模式,认同50%的安全线的重要性,才会共同努力避免这种情况的发生。
>> SRE 处理运维工作的一项准则是:在每8~12小时的on-call 轮值期间最多只处理两个紧急事件。这个准则保证了on-call工程师有足够的时间跟进紧急事件,这样SRE可以正确地处理故障、恢复服务,并且要撰写一份事后报告。
>> 相对而言,如果一个项目的紧急警报非常少,能够持续稳定运行,那么保持这么多on-call工程师可能就是浪费时间。
>> 所有的产品事故都应该有对应的事后总结,无论有没有触发警报。这里要注意的是,如果一个产品事故没有触发警报,那么事后总结的意义可能更大:因为它将揭示监控系统中的漏洞。事后总结应该包括以下内容:事故发生、发现、解决的全过程,事故的根本原因,预防或者优化的解决方案。Google 的一项准则是“对事不对人”,事后总结的目标是尽早发现和堵住漏洞,而不是通过流程去绕过和掩盖它们。
>> 在保障服务SLO的前提下最大化迭代速度
>> 在企业中,最主要的矛盾就是迭代创新的速度与产品稳定程度之间的矛盾。
>> 使用的工具是错误预算
>> 一般来说,任何软件系统都不应该一味地追求100% 可靠。因为对最终用户来说,99.999% 和 100% 的可用性是没有实质区别的(
>> 如果100% 不是一个正确的可靠性目标,那么多少才是呢?这其实并不是一个技术问题,而是一个产品问题。要回答这个问题,必须考虑以下几个方面: 基于用户的使用习惯,服务可靠性要达到什么程度用户才会满意? 如果这项服务的可靠程度不够,用户是否有其他的替代选择? 服务的可靠程度是否会影响用户对这项服务的使用模式?
>> 公司的商业部门或者产品部门必须建立起一个合理的可靠性目标。一旦建立,“错误预算”就是“1-可靠性目标”。如果一个服务的可靠性目标是99.99%,那么错误预算就是 0.01%。
>> 这个基本模型建立起来之后,许多常见的战术策略,例如灰度发布、1% AB测试等就全说得通了。这些战术性手段都是为了更合理地使用整个服务的错误预算。
>> 通过引进“错误预算”的概念,我们解决了研发团队和SRE团队之间的组织架构冲突。SRE团队的目标不再是 “零事故运行”,SRE团队和产品研发团队目标一致,都是在保障业务服务可靠性需求的同时尽可能地加快功能上线速度。这个改动虽小,意义却很大。一次“生产事故”不再是一件坏事,而仅仅是创新流程中一个不可避免的环节,两个团队通过协作共同管理它。
>> 监控系统
>> 监控系统是SRE团队监控服务质量和可用性的一个主要手段
>> 监控系统不应该依赖人来分析警报信息,而是应该由系统自动分析,仅当需要用户执行某种操作时,才需要通知用户。
>> 一个监控系统应该只有三类输出。紧急警报(alert)意味着收到警报的用户需要立即执行某种操作,目标是解决某种已经发生的问题,或者是避免即将发生的问题。工单(ticket)意味着接受工单的用户应该执行某种操作,但是并非立即执行。系统并不能自动解决目前的情况,但是如果一个用户在几天内执行这项操作,系统不会受到任何影响。日志(logging)平时没有人需要关注日志信息,但是日志信息依然被收集起来以备调试和事后分析时使用。正确的做法是平时没人会去主动阅读日志,除非有特殊需要。
>> 应急事件处理
>> 可靠性是MTTF(平均失败时间)和MTTR(平均恢复时间)的函数(参见文献[Sch15])。评价一个团队将系统恢复到正常情况的最有效指标,就是MTTR。
>> 当不可避免地需要人工介入时,我们也发现与“船到桥头自然直”的态度相比,通过事先预案并且将最佳方法记录在“运维手册(playbook)”上通常可以使MTTR 降低3倍以上。
>> 长久看来一个手持“运维宝典”经过多次演习的on-call工程师才是正确之路。虽然不论多么完备的“运维手册”也无法替代人的创新思维,但是在巨大的时间压力和产品压力下,运维手册中记录的清晰调试步骤和分析方法对处理问题的人是不可或缺的。
>> 变更管理
>> SRE的经验告诉我们,大概 70% 的生产事故由某种部署的变更而触发。变更管理的最佳实践是使用自动化来完成以下几个项目:
采用渐进式发布机制。
迅速而准确地检测到问题的发生。
当出现问题时,安全迅速地回退改动。
>> 需求预测和容量规划
>> 需求预测和容量规划简单来说就是保障一个业务有足够的容量和冗余度去服务预测中的未来需求
>> 一个业务的容量规划,不仅仅要包括自然增长(随着用户使用量上升,资源用量也上升),也需要包括一些非自然增长的因素(新功能的发布、商业推广,以及其他商业因素在内)。
>> 容量规划有几个步骤是必需的: 必须有一个准确的自然增长需求预测模型,需求预测的时间应该超过资源获取的时间。 规划中必须有准确的非自然增长的需求来源的统计。 必须有周期性压力测试,以便准确地将系统原始资源信息与业务容量对应起来。
>> 资源部署
>> 资源的部署(provisinging)是变更管理与容量规划的结合物。在我们的经验里,资源的部署和配置必须能够非常迅速地完成,而且仅仅是在必要的时候才执行,因为资源通常是非常昂贵的。
>> 增加现有容量经常需要启动新的实例甚至是整个集群,这通常需要大幅度修改现有的集群配置(配置文件、负载均衡、网络等),同时还要执行一系列测试,确保新上线的容量可以正确地服务用户。因此,新资源的部署与配置是一个相对比较危险的操作,必须要小心谨慎地执行。
>> 效率与性能
>> 高效地利用各种资源是任何赢利性服务都要关心的。
>> 因为一个服务的利用率指标通常依赖于这个服务的工作方式以及对容量的配置与部署上。
>> 一个业务总体资源的使用情况是由以下几个因素驱动的:用户需求(流量)、可用容量和软件的资源使用效率。SRE 可以通过模型预测用户需求,合理部署和配置可用容量,同时可以改进软件以提升资源使用效率。
>> 软件系统一般来说在负载上升的时候,会导致延迟升高。延迟升高其实和容量损失是一样的。当负载到达临界线的时候,一个逐渐变慢的系统最终会停止一切服务。
>> SRE的目标是根据一个预设的延迟目标部署和维护足够的容量。
小结
>> 由一个简单的想法“我是一名软件工程师,这是我如何来应付重复劳动的办法”而生
硬件
>> 物理服务器(machine)代表具体的硬件(有时候也代表一个VM 虚拟机)。
>> 软件服务器(server)代表一个对外提供服务的软件系统。
>> 物理服务器上可以运行任何类型的软件服务器。Google 并不会使用专门的物理服务器运行专门的软件服务器。
>> 采用一套集群管理系统进行资源分配,它的名称为Borg。
管理物理服务器的系统管理软件
>> 硬件故障是我们用软件系统所解决的一项主要问题。因为一个集群中包括很多硬件设备,每天硬件设备的损坏量很高。在一年内,一个单独集群中平均会发生几千起物理服务器损坏事件,会损失几千块硬盘。
>> 所以,想将硬件故障与实际业务用户隔离开来。
>> 当Borg启动一个任务的时候,它会为每一个实例安排一台物理服务器,并且执行具体的程序启动它。Borg 同时会不断监控这些实例,如果发现某个实例出现异常,其会终止该实例,并且重启它,有时候会在另外一台物理服务器上重启。
>> 因为任务实例与机器并没有一对一的固定对应关系
>> 为了解决这个问题,我们增加了一个新的抽象层。每当Borg启动某一个任务的时候,它会给每个具体的任务实例分配一个名字和一个编号,这个系统称之为Borg名称解析系统(BNS)。当其他任务实例连接到某个任务实例时,使用BNS名称建立连接,BNS系统负责将这个名称转换成具体的IP地址和端口进行连接。
>> 每个任务都需要在配置文件中声明它需要的具体资源(例如:3CPU核心,2GB 内存等)。有了这样的信息,Borg 可以将所有的任务实例合理分配在不同的物理服务器上,以提高每个物理服务器的利用率。
>> Borg还关注物理服务器的故障域(failure domain)属性。例如,Borg 不会将某个任务的全部实例都运行在某一个机柜上。因为这样一来,机柜交换机将成为整个任务的单点故障源。
>> 我们发现,一个缓慢的不断重启的实例要好过一个永远不重启一直泄露资源的实例。
>> 我们使用一个基于OpenFlow协议的软件定义网络(SDN)
>> 我们可以将整个集群的复杂路由计算从具体交换硬件上分离开来,从而降低成本。
>> 带宽控制器(Bandwidth Enforcer,BwE)负责管理所有可用带宽。优化带宽的使用的目的不仅仅是降低成本。利用中心化的路由计算,可以解决以前在分布式路由模式下难以解决的流量迁移问题
>> 为了降低分布式集群的服务延迟,我们希望能够将用户指派给距离最近的、有空余容量的数据中心处理。我们的全球负载均衡系统(GSLB)在三个层面上负责负载均衡工作: 利用地理位置信息进行负载均衡DNS请求(例如www.google.com的解析,具体描述参见第19章)。 在用户服务层面进行负载均衡,例如YouTube 和 Google Maps。 在远程调用(RPC)层面进行负载均衡(具体描述参见第20章)。
>> 通常,容量的单位是QPS,每秒请求数量
其他系统软件
>> 监控系统是服务运维中不可或缺的部分。因此,我们在数据中心中运行了多个Borgmon监控程序实例(具体描述参见10章)。Borgmon 定期从监控对象抓取监控指标(Metric)。这些监控指标可以被用来触发警报,也可以存储起来供以后观看。主要有以下几种方式使用监控系统: 对真实问题进行报警。 对比服务更新前后的状态变化:新的版本是否让软件服务器运行得更快了? 检查资源使用量随时间的变化情况,这个信息对合理制定资源计划很有用。
软件基础设施
>> Google的底层软件基础设施的设计目标是最高效地使用Google的硬件基础设施。我们的代码库大量采用了多线程设计方式,一个任务实例可以同时利用很多个CPU。每个软件服务器都有一个内置的HTTP服务,提供一些调试信息和统计信息,供在线调试、监控等使用。
>> 所有的Google服务之前都使用远程调用(RPC)通信,称为Stubby。我们目前还公布了一个开源实现,gRPC
研发环境
>> 如果一个工程师遇到了他工作的项目之外的一个基础组件的问题,他可以直接修改这个问题,向管理者提交一份改动申请(changelist,CL),等待代码评审,最后直接提交。 任何对自己项目代码的改动也需要代码评审。
>> 每当一个CL被提交时,所有被这个CL直接或间接影响到的测试都会运行一次。如果测试框架检测到一个CL破坏了其他某个系统的正常工作,测试框架会向提交者发送通知。
>> 实践自动部署机制:提交一个新版本,测试通过后,将直接部署于生产环境。
莎士比亚搜索:一个示范服务
>> 但是Google 依靠严格的测试和灰度发布流程,以及很多主动优雅降级的措施,使得我们可以为用户提供一个非常稳定的服务
>> 也就是 N+2模式: 在更新过程中,有一个任务实例将会短暂不可用,只有36个实例可提供服务。 如果另外一个物理服务器同时也出现问题,那么另外一个任务实例也受到影响,只剩35个实例可以对外服务,刚好可以满足峰值要求。
>> 假设,对用户流量的进一步观察显示我们的峰值流量其实是来自全球的。
>> 我们选择在极端情况下牺牲一些用户体验以降低成本。因为当容量不足时,GSLB会将南美洲的用户流量导向其他可用的数据中心,可以节省大概20%的硬件资源。在有条件的地方,我们还会将任务实例分散在不同的集群中,以便更好地提升可靠性。
>> 所以我们在每个地理区域都存放了Bigtable的副本。利用Bigtable的复制功能,我们可以同时达到两个目的: 当Bigtable服务出现问题时,可以利用副本提供服务。 任务实例可以利用本地Bigtable 加速数据访问。
第Ⅱ部分 指导思想
>> 本部分将描述SRE日常工作背后的指导思想—工作模式、行为方式,以及平时运维工作中关注的重点等。
>> 这一章从“风险”入手,描述了如何评估风险、管理风险,以及利用错误预算的手段来推进中立性的服务运维。
>> 服务质量目标(SLO)是SRE 的另外一个基本概念。运维行业经常会将一系列离散的概念都归结为服务质量协议(SLA),这样使得讨论变得很复杂。第4章试图将SLO与SLA区分开来,详细描述SRE是如何区分这两个术语的,同时针对应用程序性能指标的选择提供了一些建议。
>> 消除琐事(toil)是SRE的一项重要工作
>> 我们将琐事定义为无聊、重复性的运维工作,这些工作通常不具有长期价值,而且会随着服务规模的扩大而增长。
>> 第6章描述了监控的手段和目标,以及一些与具体实现无关的最佳实践。
>> 第7章描述了Google SRE进行自动化工作的方法论。这一章同时讨论了SRE在自动化过程中的一些成功和失败的案例。
>> 第8章中,我们可以看到,发布工作是整体系统稳定性的一个关键环节,因为大部分故障都是由于新的变更引起的。在这方面的投入也可以保障每次发布的顺利进行。
>> 广义软件工程中(不仅仅是运维部分)的一个关键思想是保持简单。
>> 但是不管如何,随着陈旧组件的不断下线,原来复杂的系统一定会逐渐简化。在第9章,我们详细讨论了这个主题。
>> 在保障安全的前提下,提升产品迭代速度是所有组织都想达到的目标。
>> 我们描述了从发布环节中将人工操作去除,这可以降低SRE需要做的琐事,同时可以增加系统的可靠性。
第3章 拥抱风险
>> 事实证明,超过一定值后,再提高可靠性对于一项服务(和它的用户)来说,结果可能会更差而不是更好!极端的可靠性会带来成本的大幅提升:过分追求稳定性限制了新功能的开发速度和将产品交付给用户的速度
>> 此外,用户通常不会注意到一项服务在高可靠性和极端可靠性之间的差异
>> 基于这一点,SRE旨在寻求快速创新和高效的服务运营业务之间的风险的平衡,而不是简单地将服务在线时间最大化。
管理风险
>> 高昂的成本主要存在于以下两个维度。冗余物理服务器/计算资源的成本
>> 机会成本这类成本由某一个组织承担。当该组织分配工程资源来构建减少风险的系统或功能,而非那些用户直接可用的功能时需要承担这些成本
>> 我们的目标是:明确地将运维风险与业务风险对应起来。我们会努力提高一项服务的可靠性,但不会超过该服务需要的可靠性。
>> 从某种意义上来说,我们把可用性目标同时看作风险的上限和下限。
度量服务的风险
>> Google标准做法是通过一个客观的指标来体现一个待优化的系统属性。通过设立这样一个目标,我们可客观地评价目前的系统表现以及追踪一段时间内的改进和退步
>> 服务故障可能会有很多潜在的影响,包括用户的不满、伤害,或丧失信任;直接或者间接的收入损失;品牌以及口碑上的影响;不良的新闻报道等。很明显,这些因素中的一部分很难被合理地度量。为了使这个问题在我们运行的各种类型的系统中易于处理,并且保持一致,我们选择主要关注计划外停机这个指标。
>> 对于大多数服务而言,最直接的能够代表风险承受能力的指标就是对于计划外停机时间的可接受水平。计划外停机时间是由服务预期的可用性水平所体现的,通常我们愿意用提供的“9”系列的数字来体现,比如可用性为99.9%、99.99%或99.999%。
>> 可用性=系统正常运行时间/(系统正常运行时间+停机时间)
>> 使用这个公式,我们可以计算出一年内可接受的停机时间,从而可以使可用性达到预期目标。举例来说,一个可用性目标为99.99%的系统最多在一年中停机52.56分钟,就可以达到预计的可用性目标;详情参见附录A。
>> Google所采用的故障隔离手段使得我们能够保证在任何时候、任何地方对于一个给定的服务,总是可以处理一定的用户流量。(也就是说,我们随时都是部分“在线”的)。因此,我们通过请求成功率来定义服务可用性。
>> 公式3-2:合计可用性可用性=成功请求数/总的请求数
例如,一个每天可用性目标为99.99%的系统,一天要接受2.5M个请求。它每天出现少于250个错误即可达到预计的可用性目标。
>> 通常,我们会为一项服务设定季度性的可用性目标,每周甚至每天对性能进行跟踪。我们通过寻找、跟踪和调整重要的、不可避免的偏差来使服务达到一个高层次的可用性目标。
服务的风险容忍度
>> 如何辨别服务的风险容忍度?在一个正式的环境或安全关键的系统中,服务的风险容忍度通常是直接根据基本产品或服务的定义建立的。
>> 必须与产品负责人一起努力,将一组商业目标转化为明确的可以实现的工程目标。这些商业目标会直接影响所提供服务的性能和可靠性目标。
>> 辨别消费者服务的风险容忍度
>> 我们的消费者服务通常会有一个对应的产品团队,是该服务的商业所有者。比如说,Search、Google Maps和Google Docs,它们每一个都有自己的产品经理。这些产品经理负责了解用户和业务,在市场上塑造产品的定位
>> 评价服务风险容忍度时,有许多需要考虑的因素。如下所示: 需要的可用性水平是什么? 不同类型的失败对服务有不同的影响吗? 我们如何使用服务成本来帮助在风险曲线上定位这个服务? 有哪些其他重要的服务指标需要考虑?
>> 可用性目标对于某个Google服务而言,服务的可用性目标通常取决于它提供的功能,以及这项服务在市场上是如何定位的。下面列出了要考虑的一些问题: 用户期望的服务水平是什么? 这项服务是否直接关系到收入(我们的收入或我们的客户的收入)? 这是一个有偿服务,还是免费服务? 如果市场上有竞争对手,那些竞争对手提供的服务水平如何? 这项服务是针对消费者还是企业的?
>> 一个Google Apps for Work服务的中断不仅会影响Google本身,也会影响到那些在业务上非常依赖于我们的企业。对于这类服务,我们可能会设置季度性的外部可用性目标为99.9%。同时,我们会设置一个更高的内部可用性目标,以及签署一份如果我们未能达到外部目标的处罚性协议。
>> 我们为YouTube设定了一个相比我们企业的产品更低的可用性目标,因为快速发展更加重要。
>> 故障的类型对于一项给定的服务的故障预期是另一个需要重点考虑的因素。我们的业务对于服务的停机时间的容忍程度有多高?持续的低故障率或者偶尔发生的全网中断哪一个会更糟糕?这两种类型的故障可能会导致绝对数量上完全相同的错误被返回,但可能对于业务的影响相差很大。
>> 一个提供私人信息的系统中自然发生的完全和部分服务中断的区别。假设有一个联系人管理应用程序,一种情况是导致用户头像显示失败的间歇性故障,另一种情况是将A用户的私人联系列表显示给B用户的故障。第一种情况显然是一个糟糕的用户体验,SRE会努力去快速地解决这个问题。然而,在第二种情况下,暴露私人数据的风险可能会破坏基本的用户信任。因此,在第二种情况下,在进行调试和事后的数据清理时,完全停止该服务更加恰当。
>> 对于Google提供的其他服务,有时候,我们可以接受计划内的常规的服务中断。
>> 在为每一项服务确定可用性目标时,可以考虑如下的问题: 构建和运维可用性再多一个“9”的系统,收益会增加多少? 额外的收入是否能够抵消为了达到这一可靠性水平所付出的成本?为了使这个权衡等式更精确,假设一项业务中每一个请求的价值是一样的,考虑如下的成本与收益:可用性目标:99.9%→99.99%增加的可用性:0.09%服务收入:100万美元改进可用性后的价值:100万美元×0.0009=900美元在这种情况下,如果可用性提高一个“9”的成本不到900美元,这就是合理的投资。但是,如果成本超过900美元,那么成本将超过预计增加的收入。
>> 当我们无法简单地解释可靠性和收入的关系时,可能会更难设置这些目标。这时,考虑在互联网中ISP的背景误差率可能是个不错的实用策略。如果从最终用户的角度测算故障,那么让服务的误差率低于背景误差率就是可能的。这些误差将归入给定用户的互联网链路的噪声当中。
>> 除了可用性,其他指标也可以用来确定服务的风险容忍度。了解哪些指标是重要的,哪些指标是不重要的,可以为我们在讨论风险承受能力时提供帮助。
>> Google广告系统的服务延迟是一个典型的例子。当
>> 相对延迟不敏感的AdSense服务,使得我们能够通过合并需求较少的地理区域来降低运营开销。
>> 基础设施服务的风险容忍度
>> 一个根本的区别是,基础设施组件有多个客户,而他们通常有很多不同的需求。
>> Bigtable是一个大型结构化数据分布式存储系统,一些面向消费者的服务数据直接通过它服务用户请求。这样的服务需要很低的延迟和较高的可靠性。其他团队则把Bigtable作为离线分析的数据存储使用(例如,MapReduce)。这些团队往往更关注吞吐量而非可靠性。这两个情况的风险容忍度相当不同。
>> 为了更好地了解不同类型用户的不同需求,我们可以分析每个用户对自己Bigtable请求队列的期望。
>> 故障类型低延迟的用户希望Bigtable的请求队列(几乎总是)为空,这样系统可以立刻处理每个出现的请求。(事实上,效率低下的排队过程往往是导致较高的长尾延迟的原因。)而离线分析的用户更感兴趣的是系统的吞吐量,因此用户希望请求队列永远不为空。
>> 一种在符合成本效益条件下满足这些竞争性约束的方式就是将基础设施分割成多个服务,在多个独立的服务水平上提供该服务。
>> 在Bigtable的例子中,我们可以构建两个集群:低延迟集群和高吞吐量集群。
>> 基础设施服务运维的关键战略就是明确划分服务水平,从而使客户在构建系统时能够进行正确的风险和成本权衡。
>> 这里要注意的是,我们可以使用相同的硬件和软件运行多个级别的服务。可以通过调整服务的各种特性提供不同的服务水平,如资源的数量、冗余程度、资源的地理配置,以及基础设施软件的配置。
>> 我们已经探讨了识别消费者服务和基础设施服务风险耐受能力的方法。现在,我们将继续讨论如何运用已知的风险耐受水平来通过错误预算调整系统的不可靠性。
使用错误预算的目的
>> 软件对故障的容忍度
>> 测试
>> 发布频率
>> 测试新发布的代码的最好做法就是在一个典型工作负载的服务子集中进行测试,这种做法通常被称为金丝雀测试。
>> 我们的目标是定义一个双方都同意的客观指标,该指标可以用来指导谈判的方向。一项决策越是基于数据做出的,常常就越好
>> 我们的实际做法如下: 产品管理层定义一个SLO,确定一项服务在每个季度预计的正常运行时间。 实际在线时间是通过一个中立的第三方来测算的:我们的监控系统。 这两个数字的差值就是这个季度中剩余的不可靠性预算。 只要测算出的正常在线时间高于SLO,也就是说,只要仍然有剩余的错误预算,就可以发布新的版本。
>> 好处错误预算的主要好处就是它能够激励产品研发和SRE一起找出创新和可靠性之间合理的平衡点。
>> 有比这种简单的开/关技术更巧妙和有效的方法:[2]例如,当SLO 违规导致错误预算接近耗尽时,将发布的速度减慢,或者回退到上一版本。
>> 关键点 管理服务的可靠性主要在于管理风险,而且管理风险的成本可能很高。 100%可能永远都不是一个正确的可靠性目标:不仅是不可能实现的,而且它通常比一项服务的用户期望的可靠性大得多。我们要将服务风险和愿意承担的业务风险相匹配。 错误预算在SRE和产品研发团队之间调整激励,同时强调共同责任。错误预算使得讨论发布速率更容易,同时可有效地减少任何关于事故的讨论。这样,多个团队可以毫无怨言地对生产环境风险度达成一致。
第4章 服务质量目标
>> 如果不详细了解服务中各种行为的重要程度,并且不去度量这些行为的正确性的话,就无法正确运维这个系统
>> 不管是对外服务,还是内部API,我们都需要制定一个针对用户的服务质量目标,并且努力去达到这个质量目标。
>> 我们需要利用一些主观判断结合过去的经验以及对服务的理解来定义一些服务质量指标(SLI)、服务质量目标(SLO),以及服务质量协议(SLA)。这三项分别是指该服务最重要的一些基础指标、这些指标的预期值,以及当指标不符合预期时的应对计划。
>> 本章描述了SRE团队在指标建模、指标选择,以及指标分析上采用的基本框架。
服务质量术语
>> SLI是指服务质量指标(indicator)—该服务的某项服务质量的一个具体量化指标。
>> 大部分服务都将请求延迟—处理请求所消耗的时间—作为一个关键SLI。其他常见的SLI包括错误率(请求处理失败的百分比)、系统吞吐量(每秒请求数量)等。
>> 理想情况下,SLI应该直接度量某一个具体的服务质量。但是很多时候,直接度量信息可能非常难以获取,或者无法观测,我们只能用某种指标来替代。例如,客户端的延迟数据经常是最直接的用户指标,但是由于条件限制可能只能监控服务器端的延迟数据。
>> 可用性(availability)是另外一个SRE重视的SLI,代表服务可用时间的百分比。该指标通常利用“格式正确的请求处理成功的比例”来定义,有时也称为服务产出(yield)。对数据存储系统来说,持久性(durability)—数据能够完整保存的时间—也是一个重要指标
>> 目前Google 云计算服务公开的可用性指标是“3.5个9”— 99.95% 可用。
>> SLO是服务质量目标(Objective):服务的某个SLI的目标值,或者目标范围。SLO的定义是SLI≤目标值,或者范围下限≤SLI≤范围上限。
>> 选择一个合适的SLO是非常复杂的过程。第一个困难点是很有可能无法确定一个具体的值。
>> 而且,可能不那么直观的是,这两个SLI—QPS和延迟—很可能是相关的:QPS升高通常会导致延迟升高,服务到达一定负载水平后性能下降是很常见的
>> SRE保证全球Chubby服务能够达到预定义的SLO,但是同时也会确保服务质量不会大幅超出该SLO。每个季度,如果真实故障没有将可用性指标降低到SLO之下,SRE会有意安排一次可控的故障,将服务停机。利用这种方法,我们可以很快找出那些对Chubby全球服务的不合理依赖,强迫服务的负责人尽早面对这类分布式系统的天生缺陷。
>> SLA是服务质量协议(Agreement):指服务与用户之间的一个明确的,或者不明确的协议,描述了在达到或者没有达到SLO之后的后果。这些后果可以是财务方面的—退款或者罚款—也可能是其他类型的
>> 区别SLO和SLA的一个简单方法是问“如果SLO没有达到时,有什么后果?”如果没有定义明确的后果,那么我们就肯定是在讨论一个SLO,而不是SLA
指标在实践中的应用
>> 如何来识别哪些指标对服务是最重要的呢?
>> 运维人员和最终用户各关心什么
>> 我们不应该将监控系统中的所有指标都定义为SLI;只有理解用户对系统的真实需求才能真正决定哪些指标是否有用。
>> 一般来说,四五个具有代表性的指标对系统健康程度的评估和关注就足够了。
>> 常见的服务,根据它们的相关SLI通常会归类为以下几个大类。 用户可见的服务系统,例如莎士比亚搜索服务的前端服务器通常关心可用性、延迟,以及吞吐量。换句话说:是否能正常处理请求?每个请求花费的时间是多少?多少请求可以被处理? 存储系统通常强调:延迟、可用性和数据持久性。换句话说:读写数据需要多少时间?我们是否可以随时访问数据?数据是否一段时间内还能被读取?扩展讨论参见第26章。 大数据系统,例如数据处理流水线系统,一般来说关心吞吐量和端到端延迟。换句话说:处理了多少数据?数据从输入到产出需要多少时间?(某些流水线任务还会关注某个单独处理阶段的延迟。) 所有的系统都应该关注:正确性。是否返回了正确的回复,是否读取了正确的数据,或者进行了正确的数据分析操作。正确性是系统健康程度的一个重要指标,但是它更关注系统内部的数据,而不是系统本身,所以这通常不是SRE直接负责的。
>> 指标的收集利用某种监控系统,大部分指标数据都在服务器端被收集,例如Borgmon(具体参见第10章)或者Prometheus。或者利用某种日志分析系统,例如分析日志中HTTP 500回复所占的比例。然而,某些系统可以加入对客户端数据的收集,否则可能会错失一些不影响服务器端指标,但是对用户产生影响的问题。
>> 页面JavaScript脚本导致的用户可见的延迟问题。在这个例子中,度量页面在浏览器中可用的延迟是度量用户体验的一个更好的指标。
>> 汇总为了简化和使数据更可用,我们经常需要汇总原始度量数据。汇总过程应该非常小心。
>> 简单度量也需要在某个度量时间范围内进行汇总。该度量值是应该每秒获取一次,还是每分钟内的平均值?后者可能会掩盖仅仅持续几秒的一次请求峰值。
>> 大部分指标都应该以“分布”,而不是平均值来定义。
>> 利用百分位指标可以帮助我们关注该指标的分布性:高百分位,例如99% 和99.9% 体现了指标的最差情况,而50% 则体现了普遍情况(99%百分位是指在原始数据中99%的数值都满足某种条件。例如请求延迟的99%为100ms指的是,在所有请求中,99%的请求延迟都小于100ms)。响应时间的分布越分散,意味着普通用户受到长尾请求延迟的影响就越明显,这可能预示了负载过高情况下出现的排队问题。
>> 研究显示,用户通常更喜欢速度较慢的系统,而不是一个请求速度抖动很厉害的系统,所以,某些SRE团队只关注长尾部分,因为如果99.9%的系统行为都正常的话,那50%部分就肯定也是正常的。
>> 关于统计性谬误一般来说,SRE更倾向于分析一组数据的百分比分布,而非其算术平均值。长尾效应比算术平均值更有特点,使用百分比分布能够更清晰地进行分析
>> 我们同时也不会假设数据是平均分配的,一切都必须经过验证。某些常见的直觉感觉和近似方法在这里并不适用。例如,如果分布情况和假设不一致,那么根据这个假设做出的操作就有可能频率过高,或者频率过低(例如根据请求延迟将过高的服务器自动重启
>> 指标的标准化我们建议标准化一些常见的SLI,以避免每次都要重新评估它们。任何一个符合标准定义模板的服务可以不需要再次自己定义SLI。 汇总间隔:每1分钟汇总一次 汇总范围:集群中的全部任务 度量频率:每10秒一次 包含哪些请求:从黑盒监控任务发来的HTTP GET请求 数据如何获取:通过监控系统获取服务器端信息得到 数据访问延迟:从收到请求到最后一个字节被发出
目标在实践中的应用
>> 目标在实践中的应用我们应该从思考(或者调研)用户最关心的方面入手,而非从现在能度量什么入手。用户真正关心的部分经常是度量起来很困难,甚至是不可能的,所以我们需要以某种形式近似。
>> 因此,与其选择指标,再想出对应的目标,不如从想要的目标反向推导出具体的指标。
>> 目标的定义为了更清晰地定义,SLO应该具体指出它们是如何被度量的,以及其有效条件。例如,我们可能说: 99%(在1分钟的时间范围内汇总)的Get RPC调用会在小于100ms的时间内完成(包括全部后端服务器)。 99% 的Get RPC会在100ms内完成(这一句与上一句一样,只是利用了SLI模板中的信息减少了重复信息)。如果性能曲线也很重要的话,我们可以指定多个SLO目标: 90% 的Get RPC会在1ms内完成。 99% 的Get RPC 会在10ms内完
>> 如果我们同时具有批处理用户(关注吞吐量)以及在线交互式用户(关注延迟),那么可能应该为每种负载指定单独的SLO目标: 95% 的批处理用户Set RPC 应该在1s之内完成。 99% 的交互式用户Set RPC,并且RPC负载小于 1KB 的应该在 10ms之内完成。
>> 更好的方案是使用错误预算(Error Budget)——对达不到SLO的容忍度——以天或者以周为单位计量。高层管理者可能同时也需要按月度或者季度的评估。(错误预算其实就是保证达到其他SLO的一个SLO!)
>> 通过每日(或者每周)对SLO达标程度的监控可以展示一个趋势,这样就可以在重大问题发生之前得到预警。
>> SLO不达标的频率可以用来与错误预算进行对比(
>> 目标的选择选择目标SLO不是一个纯粹的技术活动,因为这里还涉及产品和业务层面的决策,SLI和SLO(甚至SLA)的选择都应该直接反映该决策。同样的,有时候可能可以牺牲某些产品特性,以便满足人员、上线时间(time to market)、硬件可用性,以及资金的限制。
>> 提供有关可行性和风险性的建议,下面列出了一些有用的讨论。
>> 不要仅以目前的状态为基础选择目标
>> 了解系统的各项指标和限制非常重要,但是仅仅按照当前系统的标准制定目标,而不从全局出发,可能会导致团队被迫长期运维一个过时的系统,没有时间去推动架构重构等任务。
>> 保持简单
>> SLI中过于复杂的汇总模式可能会掩盖某种系统性能的变化,同时也更难以理解。
>> 避免绝对值
>> SLO越少越好
>> 应该仅仅选择足够的SLO来覆盖系统属性,一定要确保每一个SLO都是必不可少的:如果我们无法针对某个SLO达标问题说服开发团队,那么可能这个SLO就是不必要的[4]。
>> 不要追求完美
>> 我们可以随着时间流逝了解系统行为之后优化SLO的定义。刚开始可以以一个松散的目标开始,逐渐收紧。这比一开始制定一个困难的目标,在出现问题时放松要好得多。
>> SLO是一个很重要的杠杆:要小心使用。
>> 控制手段SLI和SLO在决策系统运维时也非常有用:1.监控并且度量系统的SLI。2.比较SLI和SLO,以决定是否需要执行操作。3.如果需要执行操作,则要决定究竟什么操作需要被执行,以便满足目标。4.执行这些操作。
>> SLO可以建立用户预期通过公布SLO可以设置用户对系统行为的预期。用户(以及潜在用户)经常希望知道他们可以预期的服务质量,以便理解该服务是否能够满足他们的要求
>> 为了让用户拥有正确的预期,我们可以考虑使用以下几种策略:留出一定的安全区
>> 对内使用更高的SLO,对外使用稍低的SLO可以留出一些时间用来响应问题。SLO缓冲区也可以用来进行可能影响系统属性的重构,例如降低成本以及方便运维等,缓冲区保护我们不会对用户产生直接影响。
>> 实际SLO也不要过高
第5章 减少琐事
>> 如果系统正常运转中需要人工干预,应该将此视为一种Bug。
琐事的定义
>> 一些管理类杂务是必须做的,不应该被归类为琐事:这些是流程开销(overhead)。流程开销通常是指那些和运维产品服务不直接相关的工作,包括团队会议、目标的建立和评估[6]、每周总结[7]以及人力资源的书面工作等。
>> 到底什么是琐事?琐事就是运维服务中手动性的,重复性的,可以被自动化的,战术性,没有持久价值的工作。而且,琐事与服务呈线性关系的增长
>> 战术性的琐事是突然出现的、应对式的工作,而非策略驱动和主动安排的。处理紧急警报是琐事。我们可能永远无法完全消除这种类型的工作,但我们必须继续努力减少它。
>> 没有持久价值如果在你完成某项任务之后,服务状态没有改变,这项任务就很可能是琐事。
为什么琐事越少越好
>> SRE公开50%这个目标是因为如果不加以控制,琐事会变得越来越多,以至于迅速占据我们每个人100%的时间。减少琐事和扩大服务规模的工作就是 SRE 中的E(Engineering)
>> 任何一个SRE在参与on-call时都会承担一定程度的琐事。
>> 来自SRE的数据显示,琐事的最大来源就是中断性工作(即与服务相关的非紧急的邮件和电子邮件)。另一个主要来源是on-call(紧急的),紧随其后的是发布和数据更新。
什么算作工程工作
>> 工程工作(Engineering)是一种新颖的、本质上需要主观判断的工作。它是符合长期战略的,会对你的服务进行长久性的改善的工作。工程工作通常是有创新性和创造性的,着重通过设计来解决问题,解决方案越通用越好。工
>> 典型的SRE活动分为如下几类。软件工程编写或修改代码,以及所有其他相关的设计和文档工作。例如,编写自动化脚本,创造工具或框架,增加可扩展性和可靠性的服务功能,或修改基础设施代码以使其更稳健。系统工程配置生产系统、修改现存配置,或者用一种通过一次性工作产生持久的改进的方法来书写系统文档。例如,监控的部署和更新、负载均衡的配置、服务器配置、操作系统的参数调整和负载均衡器的部署。系统工程还包括与研发团队进行的架构、设计和生产环境方面的咨询工作。
>> 琐事与运维服务相关的重复性的、手工的劳动。流程负担与运维服务不直接相关的行政工作。例如招聘、人力资源书面工作、团队/公司会议、任务系统的定期清理工作、工作总结、同行评价和自我评价,以及培训课程等。按全年或者数个季度来说,每个SRE需要花费至少50%的时间在工程工作中。
术语定义
>> 监控(monitoring)收集、处理、汇总,并且显示关于某个系统的实时量化数据,例如请求的数量和类型,错误的数量和类型,以及处理用时,应用服务器的存活时间等。白盒监控(white-box monitoring)依靠系统内部暴露的一些性能指标进行监控。包括日志分析、Java虚拟机提供的监控接口,或者一个列出内部统计数据的HTTP接口进行监控。黑盒监控(black-box monitoring)通过测试某种外部用户可见的系统行为进行监控。监控台页面(dashboard)提供某个服务核心指标一览服务的应用程序(一般是基于Web的)。该应用程序可能会提供过滤功能(filter)、选择功能(selector)等,但是最主要的功能是用来显示系统最重要的指标。该程序同时可以显示相应团队的一些信息,包括目前工单的数量、高优先级的Bug列表、目前的on-call工程师和最近进行的生产发布等。警报(alert)目标对象是某个人发向某个系统地址的一个通知。
>> 这些警报被分类为:工单、E-mail警报[9],以及紧急警报(page)。
>> 根源问题(root cause)指系统(软件或流程)中的某种缺陷。这个缺陷如果被修复,就可以保证这种问题不会再以同样的方式发生。
>> 可能自动化程度不够,软件在异常输入下崩溃,以及对生成配置文件的脚本测试不足等。这里每一个因素都是一个根源问题,并且每一个都需要被修复。
为什么要监控
>> 为什么要监控
>> 分析长期趋势
>> 数据库目前的数据量,以及增长速度。又例如每日活跃用户的数量增长的速度。跨时间范围的比较,或者是观察实验组与控制组之间的区别
>> 临时性的回溯分析(也就是在线调试)
>> 监控与报警可以让一个系统在发生故障时主动通知我们,或者能够告诉我们即将发生什么。
>> 高效的警报系统应该提供足够的信息,并且误报率非常低。
对监控系统设置合理预期
>> Google趋向于使用简单和快速的监控系统配合高效的工具进行事后分析。我们会避免任何“魔法”系统—例如试图自动学习阈值或者自动检测故障原因的系统。
>> 我们坚持监控系统规则越简单越好,同时要求这些监控规则可以检测某个非常简单、具体,但是严重的异常情况
>> 监控数据的其他用处还包括容量规划、流量预测,用于这些方面的监控规则对错误和稳定性的要求更低,也就可以稍微复杂一些。
>> 针对某个试验功能的数据观测,可能时间跨度非常长(数月甚至数年),取样率也很低,这种用途可以容忍一定的错误率,因为这些偶尔出现的错误不会掩盖真正的长期趋势。
>> 但是监控系统中最重要的一点就是整个“生产故障,人工处理紧急警报,简单定位和深入调试”过程必须要保持非常简单,必须能被团队中任何一个人所理解。
>> 同样的,监控系统信噪比应该很高,发出紧急警报的组件需要非常简单而且可靠。产生警报的监控系统规则应该非常容易理解,同时代表一个清晰的故障场景。
现象与原因
>> 监控系统应该解决两个问题:什么东西出故障了,以及为什么出故障。
>> “现象”和“原因”的区分是构建信噪比高的监控系统时最重要的概念。
黑盒监控与白盒监控
>> Google大量依赖白盒监控,黑盒监控用得虽然不多,但都是在关键地方使用。黑盒监控与白盒监控最简单的区别是:黑盒监控是面向现象的,代表了目前正在发生的—而非预测会发生的—问题,即“系统现在有故障”。白盒监控则大量依赖对系统内部信息的检测,如系统日志、抓取提供指标信息的HTTP节点等。白盒监控系统因此可以检测到即将发生的问题及那些重试所掩盖的问题等。
网友评论