SRE Google运维解密 第一章
译者序
SRE 是一群天生的怀疑论者,我们怀疑一切宣传起来 "高大上" 的技术,以及任何 "神奇" 的产品一一我们只想看具体的设计架构、实现细节,以及真实的监控图表。SRE 在保障系统可靠性方面并没有什么万能药,有的只是这种极强的务实态度 (pragmatic)。
这种务实的态度决定了 SRE 会认真对待运维问题。在设计评审中,他们会认真推演各种灾难场景。在每周例会时,他们又会讨论如何消除和防范事故发生、优化各种警报策略以及增强自动化功能。在平时工作中,他们则会精心维护团队的各种文档和项目源代码,一点一点地提高服务质量。
前言
系统运维本质上是人与计算机共同参与的一项系统性工程。
这本书中没有万能药,没有什么东西能解决一切问题,但是这恰恰是本书的宗旨:相比最后的软件结果、架构设计而言,真实的设计过程、作者本身的思考经历更有价值。实现细节永远只是短暂存在的,但是文档化的设计过程却是无价之宝。
序言
软件工程有的时候和养孩子类似:虽然生育的过程是痛苦和困难的,但是养育孩子成人的过程才是真正需要花费绝大部分精力的地方。
但是,传统软件工程专业花费了很多精力讨论软件的开发过程,而不是其后的维护过程。
有统计显示,一个软件系统的40%~90% 的花销其实是花在开发建设完成之后不断维护过程中的。行业内流行的一个说法是;一个系统如果已经开发完成,部署在生产环境上,那么它就是 "稳定的",就不需要那么多工程师花费精力去优化、维护。我们认为这个说法是错误的。从这个视角出发,我们认为如果软件工程职业主要专注于设计和构建软件系统,那么应该有另外一种职业专注于整个软件系统的生命周期管理。从其设计一直到部署,历经不断改进,最后顺利退役。这样一种职业必须具备非常广泛的技能,但是和其他职业的专注点都不同。Google 将这个职位称为站点可靠性工程师(SRE,Site Reliability Engineering)。
-
首先,也是最重要的一点,SRE 是工程师 (engineer)。SRE 使用计算机科学和软件工程手段来设计和研发大型、分布式计算机软件系统。有的时候 SRE 和产品研发团队共同工作,其他时候我们需要开发这些系统的额外组件:例如备份系统和负载均衡系统等。理想情况下,同时推进这些组件在多个项目中复用。还有的时候我们的任务是想出各种各样的办法用现有组件解决新的问题
-
其次,SRE 的关注焦点在于可靠性。(在我们的讨论中:可靠性是指某个系统能够在指定环境下,成功持续执行某个功能指定的时间的概率)SRE专注于对其负责的软甲系统架构设计、运维流程的不断优化,让这些大型软件系统运行得更可靠,扩展性更好,能够有效地利用资源。但是,SRE并不是无止境地追求完美:当一个系统已经 “足够可靠“ 的时候,SRE通常将精力转而投入到研发新的功能和创造新的产品中。
-
最后,SRE 的主要工作是运维在分布式集群管理系统上运行得具体业务服务。
虽然我们在这里将 SRE 的职位定义得比较宽泛,但是在这样一个互联网业务高速发展的时代,这个职位的出现毫不奇怪。同样,虽然在应用系统运营维护的过程中有数不清的重要环节需要关注,我们最关注的是“可靠性”这一点也不奇怪。在 Web 服务领域里对服务器端软件的优化和修改是相对可控的,变更管理与生产安全又结合得非常紧密种类似于SRE 的职业早晚会在这个环境下诞生。
如果一定要为 SRE 寻找一个起源的话,谁才能够被称为世界上第一个 SRE 呢?
我们选择了 Margaret Hamilton,MIT 教授,参与了阿波罗登月计划的软件开发工作。她的工作具有现代 SRE 的一切特性。(Appllo-8 事故)
第一部分 概览
第一章介绍
系统管理员模式
雇佣系统管理员(sysadmin) 运维复杂的计算机系统,是行业内一直以来的普遍做法。
这些系统管理员负责将现成的软件组件部署于生产环境中,对外提供某种业务服务。系统管理员的主要工作在于应对系统中产生的各种需要人工干预的事件,以及来自业务部门的变更需求。
系统管理员的日常工作与研发工程师相差甚远,通常分属两个不同的部门;开发部(Dev)和运维部(Ops)。
这种模型具有许多优势。对新公司来说,这种模式在行业内具有广泛的应用案例可供参考。但是,很少有人提及这样做以及相应造成 Dev/Ops 分离的团队模型存在一些无法避免的问题。下面从两个大的方面阐述:
-
直接成本。由于系统管理员团队大部分依赖人工处理系统维护事件以及变更的实施。随着系统复杂度的增加,部署规模的扩大, 团队的大小基本与系统负载成线性相关,共同增长。
-
间接成本:从本质上讲,由于研发团队和运维团队背景各异,技术能力与工具使用习惯上差距巨大,工作目标也截然不同。对产品的可靠程度要求理解不同,对某项操作的危险程度评估与可能的技术防范措施也有截然不同的理解。这些细节上的分歧积累起来,最后逐渐演变成目标与方向上的分歧及形成内部沟通问题,甚至最后上升到部门之间的信任与尊重层面。
传统的研发团队和运维团队分歧的焦点主要在软件新版本、新配置的变更的发布速度上。研发部门最关注的是如何能够更快速地构建和发布新功能。运维部门更关注的是如何能在他们值班期间避免发生故障。由于绝大部分生产故障都是由于部署某项变更导致的一。不管是部署新版本,还是修改配置,甚至有时只是因为改变了用户的某些行为造成了负载流量的配比变化而导致故障。这两个部门的目标从本质上来说是互相矛盾的。
在现实生活中,公司内部这两股力量只能用最传统的政治斗争方式来保障各自的利益。
运维团队常常宣称:任何变更上线前必须经过由运维团队制定的流程,这有助于避免事故的发生。例如;运维团队会列出一个非常长的检查清单,历数所有以前曾经出现过的生产事故,要求研发团队在上线任何功能之前必须将所有这些事故模拟一遍,确保不会重现。(这个清单通常没有任何标准,每项事故的可重现程度、问题价值并不一定是一致的)
而开发团队吃过苦头之后也很快找到了自己的应对办法:开发团队宣称他们不再进行大规模的程序更新,而是逐渐转为功能开关调整、增量更新,以及补丁化。(采用这些名词的唯一目的,就是为了绕过运维部门设立的各种流程,从而能更快地上线新功能)
Google 的解决之道:SRE
SRE团队成员具有如下特点:
- 对重复性、手工性的操作有天然的排斥感
- 有足够的技术能力快速开发出软件系统以替代手工操作
Google 为整个 SRE团队所做的所有传统运维工作设立50%的上限值。传统运维工作包括;工单处理、手工操作等。设立这样一个上限值确保了SRE 团队有足够的时间改进所维护的服务,将其变得更稳定和更易于维护。这个上限值并不是目标值。随着时间推移,SRE 团队应该倾向于将基本的运维工作全部消除,全力投入在研发任务上。因为整个系统应该可以自主运行,可以自动修复问题。我们的终极目标是推动整个系统趋向于无人化运行,而不仅仅是自动化某些人工流程。
DevOps 还是 SRE ?
DevOps 是 SRE 核心理念的普适版,可用于更广范围内的组织结构、管理结构和人员安排。
同时,SRE 是 DevOps 模型在 Google 的具体实践,带有一些特别的扩展。
SRE 方法论
一般来说:SRE团队要承担以下几类职责:可用性改进,延迟优化,性能优化,效率优化,变更管理,监控,紧急事务处理以及容量规划与管理。
1)确保长期关注研发工作
SRE 处理运维工作的一项准则是;在每 8~12 小时的 on-call 轮值期间最多只处理两个紧急事件。这个准则保证了 on-call(值班/紧急待命) 工程师有足够的时间跟进紧急事件,这样 SRE 可以正确地处理故障、恢复服务,并且要撰写一份事后报告。如果一次轮值过程中处理的问题过多,那么每个问题就不可能被详细调查清楚,运维工程师甚至没有时间从中学习。
所有的产品事故都应该有对应的事后总结,无论有没有触发警报。这里要注意的是:如果一个产品事故没有触发警报,那么事后总结的意义可能更大(因为它将揭示监控系统中的漏洞)。事后总结应该包括以下内容;事故发生、发现、解决的全过程,事故的根本原因,预防或者优化的解决方案。Google 的一项准则是“对事不对人”,事后总结的目标是尽早发现和堵住漏洞,而不是通过流程去绕过和掩盖它们。
2)在保证服务 SLO 的前提下最大化迭代速度
在企业中,最主要的矛盾就是迭代创新的速度与产品稳定程度之间的矛盾。
在 SRE 模型中,我们选择正面面对这种矛盾,使用的工具是错误预算。
如果 100% 不是一个正确的可靠性目标,那么多少才是呢?这其实并不是一个技术问题,而是一个产品问题。要回答这个问题,必须考虑以下几个方面:
- 基于用户的使用习惯,服务可靠性要达到什么程度用户才会满意?
- 如果这项服务的可靠程度不够,用户是否有其他的替代选择?
- 服务的可靠程度是否会影响用户对这项服务的使用模式?
公司的商业部门或者产品部门必须建立起一个合理的可靠性目标。一旦建立,"错误预算" 就是 "1-可靠性目标"。如果一个服务的可靠性目标是 99.99%
,那么错误预算就是 0.01%
。这意味着产品研发部门和 SRE 部门可以在这个范围内将这个预算用于新功能上线或者产品的创新等任何事情。
错误预算可以用于什么范畴呢?研发团队需要用这个预算上线新功能,吸引新用户。理想情况下,我们应该使用错误预算来最大化新功能上线的速度,同时保障服务质量。
通过引进 "错误预算" 的概念,我们解决了研发团队和 SRE 团队之间的组织架构冲突,SRE 团队的目标不再是 "零事故运行",SRE 团队和产品研发团队目标一致,都是在保障业务服务可靠性需求的同时尽可能地加快功能上线速度。
3)监控系统
监控系统是 SRE 团队监控服务质量和可用性的一个主要手段。所以,监控系统的设计策略值得着重讨论。最普遍的和传统的报警策略是针对某个特定的情况或者监控值,一旦出现情况或者监控值超过阙值就触发 E-mail 警报。但是这样的报警策略并不是非常有效:一个需要人工阅读邮件和分析警报来决定目前是否需要采取某种行动的系统从本质上就是错误的。监控系统不应该依赖人来分析警报信息,而是应该由系统自动分析,仅当需要用户执行某种操作时,才需要通知用户。
一个监控系统应该只有三类输出:
- 紧急警报(alert):意味着收到警报的用户需要立即执行某种操作,目标是解决某种已经发生的问题,或者是避免即将发生的问题
- 工单(ticker):意味着接受工单的用户应该执行某种操作,但是并非立即执行。系统并不能自动解决目前的情况,但是如果一个用户在几天内执行这项操作,系统不会受到任何影响。
- 日志(logging):平时没有人需要关注日志信息,但是日志信息依然被收集起来以备调试和事后分析时使用。正确的做法是平时没人会去主动阅读日志,除非有特殊需要。
4)应急事件处理
可靠性是 MTTF(平均失败时间)和 MTTR(平均恢复时间)的函数。评价一个团队将系统恢复到正常情况的最有效指标,就是 MTTR。
任何需要人工操作的事情都只会延长恢复时间。一个可以自动恢复的系统即使有更多的故障发生,也要比事事都需要人工干预的系统可用性更高。当不可避免地需要人工介入时,我们也发现与 "船到桥头自然直" 的态度相比,通过事先预案并且将最佳方法记录 "运维手册 (playbook)"上通常可以使 MTTR 降低3倍以上。
在巨大的时间压力和产品压力下,运维手册中记录的清晰调试步骤和分析方法对处理问题的人是不可或缺的。
5)变更管理
SRE 的经验告诉我们,大概 70% 的生产事故由某种部署的变更而触发。
变更管理的最佳实践是使用自动化来完成以下几个项目:
- 采用渐进式发布机制。
- 迅速而准确地检测到问题的发生。
- 当出现问题时,安全迅速地回退改动。
6)需求预测和容量规划
需求预测和容量规划简单来说就是保障一个业务有足够的容量和冗余度来服务预测中的未来需求。一个业务的容量预测,不仅仅要包括自然增长(随着用户使用量上升,资源用量也上升),也需要包括一些非自然增长得因素(新功能的发布,商业推广,以及其他商业因素在内)。
容量规划有几个步骤是必需的:
- 必须有一个准确的自然增长需求预测模型,需求预测的时间应该超过资源获取的时间。
- 规划中必须有准确的非自然增长得需求来源的统计。
- 必须有周期性压力测试,以便准确地将系统原始资源信息与业务容量对应起来。
7)资源部署
资源的部署(provisinging)是变更管理与容量规划的结合物。在我们的经验里,资源的部署和配置必须能够非常迅速地完成,而且仅仅是在必要的时候才执行,因为资源通常是非常昂贵的。而且这个部署和配置的过程必须要确保能够正确地执行完毕,否则资源就仍然处于不可用状态。增加现有容量经常需要启动新的实例甚至是整个集群,这通常需要大幅度修改现有的集群配置(配置文件、负载均衡、网络等),同时还要执行一系列测试,确保新上线的容量可以正确地服务用户。因此,新资源的部署与配置是一个相对比较危险的操作,必须要小心谨慎地执行。
8)效率与性能
高效地利用各种资源是任何赢利性服务都要关心的。因为 SRE 最终负责容量的部署和配置,因此SRE 也必须承担起任何有关利用率的讨论及改进。因为一个服务的利用率指标通常依赖于这个服务的工作方式以及对容量的配置与部署上。如果能够通过密切关注一个服务的容量配置策略,进而改进其资源利用率,这可以非常有效地降低系统的总成本。
一个业务总体资源的使用情况是由以下几个因素驱动的;用户需求 (流量)、可用容量和软件的资源使用效率。SRE 可以通过模型预测用户需求,合理部署和配置可用容量时可以改进软件以提升资源使用效率。通过这三个因素能够大幅度推动一个服务的效率提升(但是并非全部)。
软件系统一般来说在负载上升的时候,会导致延迟升高。当负载到达临界线的时候,一个逐渐变慢的系统最终会停滞一切服务。
SRE 的目标是根据一个预设的延迟目标部署和维护足够的容量。
SRE 和产品研发团队应该共同监控和优化整个系统的性能,这就相当于给服务增加容量和提升效率了.