google-sre

参考:








Foreword

100%的可用性是不现实的,需要达到这个目标的成功通常远超于所能获得的价值,所以Google会针对每种产品设定一个错误预算(容错率),既能保证用户体验又不影响创新和部署的速度。

实现细节永远支持短暂存在的,但是文档化的设计过程确实无价之宝。

可靠性应该是任何产品设计中最基本的概念:任何一个系统如果没有人能够稳定地使用,就没有存在的意义。

当一个系统已经足够可靠的时候,SRE通常将精力转而投入到研发新的功能和创造新的产品。


对一些中小型企业来说,企业内部可能已经有这样的一组人在做着与SRE非常类似的工作。这些人可能并不叫SRE这个名字,甚至可能没有受到管理层的重视。在这样的企业中,提高可靠性最好的办法往往就是去认可这些人的工作,并配备足够的激励机制。在牛顿被世界正式认可为物理学家之前,他经常被称作是最后的炼金术士。

只有靠着对细节的不断关注,做好充足的灾难预案和准备工作,时刻警惕着,不放过一切机会避免灾难发生。这就是SRE最重要的理念。








介绍

传统的研发团队和运维团队分歧的焦点主要在软件版本、新配置的变更的发布速度上。研发部门最关注的是如何能够更快速地构建和发布新功能。运维部门更关注的是如何能在他们值班期间避免发生故障。由于绝大部分生产故障都是由于部署某项变更导致的——不管是部署新版本,还是修改配置。这两个部门的目标从本质上来说是互相矛盾的。

极端来说,研发部门想要随时随地发布新功能,没有任何阻拦。而运维部门则想要一旦一个东西在生产环境中正常工作了,就不再进行任何改动。由于两个部门使用的语境不同,对风险的定义也不一致。




google解决之道

SRE

SRE团队成员有如下特点:

  • 对重复性、手工性的操作有天然的排斥感
  • 有足够的技术能力快速开发出软件系统以替代手动操作

从本质上来说,SRE就是在用软件工程的思维和方法论完成以前由系统管理员团队手动完成的任务。这些SRE倾向于通过设计、构建自动化工具来取代人工操作。

SRE模型成功的关键在于对工程的关注。如果没有持续的、工程化的解决方案,运维的压力就会不断增加,团队也就需要更多的人来完成工作。如果一个产品非常成功,用户流量越来越大,就需要更多的团队成员来重复进行同样的事情。

为了避免这一点,运维团队必须有足够的时间编程,否则他们就会被运维工作所淹没。因此,Google为整个SRE团队所做的所有传统运维工作设立了一个50%的上限值。传统运维工作包括:工单处理、手动操作等。设立这样一个上限值确保了SRE团队有足够的时间改进所维护的服务,将其变得更稳定和更易于维护。

这个上限值并不是目标值。随着时间的推移,SRE团队应该倾向于将基本的运维工作全部消除,全力投入在研发任务上。因为整个系统可以自主运行,可以自动修复问题。我们的终极目标是推动整个系统趋向于无人化运行,而不仅仅是自动化某些人工流程。

Google的经验法则是,SRE团队必须将50%的精力花在真实的开发工作上。保障有足够的时间和精力去进行真正有创造性的、自主的研发工作。同时,也保障了SRE团队有足够的运维经验,从而让他们设计出切实解决问题的系统。

由于SRE模型中为了提高可靠性需要采取一些与常规做法违背的做法,所以需要强有力的管理层支持才能推行下去。




SRE方法论

一般来说,SRE团队要承担以下职责:

  • 可用性改进
  • 延迟优化
  • 性能优化
  • 效率优化
  • 变更管理
  • 监控
  • 紧急事务处理
  • 容量规划与管理




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

考虑可靠性的几个方面:

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

通过引进错误预算的概念,SRE团队的目标不再是零事故运行,SRE团队和产品研发团队目标一致,都是在保障业务服务可靠性需求的同时尽可能地加快功能上线速度。这个改动虽小,意义却很大。一次生产事故不再是一件坏事,而仅仅是创新流程中 一个不可避免的环节。



监控系统

监控系统是SRE团队监控服务质量和可用性的一个主要手段。监控系统不应该依赖人来分析警报信息,而是应该由系统自动分析,仅当需要用户执行某种操作时,才需要通知用户。




应急事件处理

可靠性是 MTTF(平均失败时间) 和 MTTR(平均恢复时间)的函数,评价一个团队将系统恢复到正常情况的最有效指标,就是MTTR。

一个可以自动恢复的系统即使有更多的故障发生,也要比事事都需要人工干预的系统可用性高。




变更管理

SRE的经验告诉我们,大概70%的生产事故由某种部署的变更而触发。变更管理的最佳实践是使用自动化来完成以下项目:

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




需求预测和容量规划

需求预测和容量规划,简单来说就是保障一个业务有足够的容量和冗余度去服务预测中的未来需求。

容量规划有几个步骤是必须的:

  • 必须有一个准确的自然增长需求预测模型,需求预测的时间应该超过资源获取的时间。
  • 规划中必须有准确的非自然增长的需求来源统计。
  • 必须有周期性压力测试,以便准确地将系统原始资源信息与业务容量对应起来。




资源部署

资源的部署是变更管理与容量规划的结合物。资源通常是非常昂贵的。




效率与性能

高效地利用各种资源是任何盈利性服务都要关心的。如果能够通过密切关注一个服务的容量配置策略,进而改进起资源利用率,这可以非常有效地降低系统的总成本。

软件系统一般来说在负载上升的时候,会导致延迟升高。延迟升高其实和容量损失是一样的。当负载到达临界线时,一个逐渐变慢的系统最终会停止一切服务。换句话说,系统此时的延迟已经是无穷大了。SRE的目标是根据一个预设的延迟目标部署和维护足够的容量。








SRE视角

硬件

Google的大部分计算资源都存放在自主设计的数据中心中,拥有自己设计的供电系统、制冷系统、网络系统以及计算机硬件。

  • 物理服务器(machine): 代表具体的硬件
  • 软件服务器(server): 代表一个对外提供服务的软件系统

物理服务器上可以运行任何类型的软件服务器。Google使用一套集群管理系统进行资源分配,名称为Borg。这玩意应该是k8s的前身。




管理物理服务器的系统管理软件

管理物理服务器

为了管理和控制硬件设备,我们开发了一套大规模部署的系统管理软件。Borg,是一个分布式的集群操作系统。与Apache Mesos类似,Borg负责在集群层面管理任务的编排工作。

有些读者可能了解Borg的下一代,Kubernetes。

Borg不会将某个任务的全部实例都运行在某一个机柜上,避免单点故障。

如果一个任务实例的资源使用超出了它的分配范围,Borg会杀掉这个实例,并且重启它。我们发现,一个缓慢的不断重启的实例要好过一个永远不重启一直泄露资源的实例。




存储

存储系统负责向用户提供一套简单易用、可靠的集群存储服务。




网络

为了降低分布式集群的服务延迟,我们希望能够将用户指派给距离最近、用空余量的数据中心处理。

Google的全球负载均衡系统在三个层面上负责负载均衡工作:

  • 利用地理位置进行负载均衡DNS请求(如google.com)
  • 在用户服务层面进行负载均衡(如Youtube)
  • 在远程调用(RPC)层面进行负载均衡




其它系统软件

分布式锁

Chubby可以处理异地、跨机房的锁请求。




监控与告警

监控系统是服务运维中不可或缺的部分。

主要有以下几种方式使用监控系统:

  • 对真实问题进行报警
  • 对比服务更新前后的状态变化:新版本是否让软件服务器运行的更快了?
  • 检查资源使用量随时间的变化情况,这个信息对合理指定资源计划很有用。




软件基础设施

Google的底层软件基础设施的设计目标是最高效地使用Google的硬件设施。

所有的Google服务之前都是用远程调用(RPC)通信,成为Stubby。开源实现是gRPC。

通常来说,一个软件服务器从该服务的前端接收RPC请求,同时将一些RPC发往该服务器的后端。




RPC

RPC(Remote Process Call),远程过程调用。

通过RPC框架,我们可以像调用本地函数/方法一样滴调用远程机器上的函数和方法。

也就是说两台服务器A, B,一个应用部署在A上,想要调用B上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。

就是要像调用本地的函数一样去调用远程函数。

gRPC是Google开源的一个RPC框架。




研发环境

除了一些开源项目之外,其它Google软件工程师使用同一个软件仓库。

  • 如果一个工程师遇到了他工作项目之外的一个基础组件的问题,他可以直接修改这个问题,向管理者提交一份改动申请,等待代码评审,最后直接提交修改
  • 任何对自己项目代码的改动也需要代码评审








拥抱风险

你可能认为Google会试图构建一个百分百可靠的服务。事实证明,超过一定值后,再提高可靠性对于一项服务来说,结果可能会更差。极端的可靠性会带来成本的大幅提升:过分追求稳定性限制了新功能的开发速度和将产品交付给用户的速度,并且很大程度地增加了成本,这反过来又减少了一个团队可以提供的新功能的数量。

SRE旨在寻求快速创新和高效的服务运营业务之间的风险的平衡,而不是简单地将服务在线时间最大化。这样,我们可以优化用户的整体幸福感,平衡系统的功能、服务和性能。




管理风险

成本:

  • 冗余服务器/计算资源的成本
  • 机会成本

在SRE团队中,我们管理服务的可靠性很大程度上是通过管理风险来进行的。




度量服务的风险

Google的标准做法是通过一个可断的指标来体现一个待优化的系统属性。

可用性 = 系统正常运行时间 / (系统正常运行时间+停机时间)

然而,在Google内部,基于时间的可用性通常是毫无意义的。因为我们需要着眼全球范围内的分布式服务。Google所采用的故障隔离手段使得我们能够保证在任何时候、任何地方对于一个给定的服务,总是可以处理一定的用户流量。(也就是说,随时都是部分在线的)。

可用性 = 成功请求数 / 总的请求数

在一个典型的应用中,不是所有的请求都是平等的。




服务的风险容忍度

为了辨别服务的风险容忍度,SRE必须于产品负责人一起努力,将一组商业目标转化为明确的可以实现的工程目标。


辨别消费者服务的风险容忍度

评价服务风险容忍度时,有许多需要考虑的因素。如下:

  • 需要的可用性水平是什么?
  • 不同类型的失败对服务有什么不同的影响?
  • 我们如何使用服务成本来帮助在风险曲线上定位这个服务?
  • 有哪些其它重要的服务指标需要考虑?




基础设施服务的风险容忍度

  • 可用性目标水平
  • 故障类型
  • 成本


  • 软件对故障的容忍度
  • 测试
  • 发布频率
  • 金丝雀测试的持续时间和大小








服务目标质量

需要制定一个针对用户的服务质量目标,并且努力地去达到这个质量目标。

服务质量指标(SLI)、服务质量目标(SLO)、服务之里昂协议(SLA)。

事先选择好合适的指标有助于在故障发生时帮助SRE进行更好地决策,同时为SRE团队判断系统是否正常提供帮助。




指标

指标的标准化

  • 汇总间隔:每一分钟汇总一次
  • 汇总范围:集群中的全部任务
  • 度量频率:每10秒一次
  • 包含哪些请求
  • 数据如何获取
  • 数据访问延迟








减少琐事

SRE要把更多时间花费在长期项目研发上,而非日常运维中。因为术语日常运维可能会被误解,这是使用一个专有名称——琐事(toil)。

一些管理类杂务是必须做的,不应该被归类于琐事,这些事流程开销(overhead)。

到底什么是琐事?琐事就是运维服务中手动性的,重复性的,可以被自动化的,战术性,没有持久价值的工作。

SRE的一个公开目标是保持每个SRE的工作时间中运维工作(琐事)的比例低于50%。SRE至少要花50%的时间在工程项目上,以减少未来的琐事或增加服务功能。增加服务功能包括提高可靠性、性能、利用率,同时也会进一步消除琐事。

SRE公开50%这个目标是因为如果不加以控制,琐事会变得越来越多,以至于迅速占据我们每个人100%的时间。减少琐事和扩大服务规模的工作就是SRE中的E(Engineering)。

SRE的角色中,琐事是不可避免的。少量的琐事不是什么大问题,但一旦琐事变多,就有害了。








分布式系统的监控

术语

一些通用的术语:

  • 监控(monitoring)
  • 白盒监控(white-box)
  • 黑盒监控(black-box)
  • 监控台页面(dashboard)
  • 警报(alert)
  • 根源问题(root cause)
  • 节点或机器(node/machine)
  • 推送(push)




现象与原因

监控系统应该解决两个问题:

  • 现象:什么东西出故障了?
  • 愿意你:为什么出故障了?

现象和原因的却分是构建信噪比高的监控系统时最重要的概念。




黑盒与白盒

黑盒是面向现象的,代表了目前正在发生的问题,而非预测发生的问题。即系统现在有故障。

白盒监控大量依赖对系统内部信息的检测,如系统日志、抓取提供指标信息的HTTP节点等。因此可以检测到即将发生的问题,以及那些重试所掩盖的问题等。

这里应该注意,在一个多层系统中,某一个服务的现象是另一个服务的原因。如数据库性能问题。




四个黄金指标

监控系统的4个黄金指标分别是:

  • 延迟
  • 流量
  • 错误
  • 饱和度




关于长尾效应

构建监控系统时,很多人倾向于采用某种量化指标的平均值。区分平均值的慢和长尾效应的慢的一个简单方法是将请求按延迟分组计数。




度量指标

当为监控系统和报警系统新增规则时,以下问题有助于减少误报:

  • 该规则是否能够检测到一个目前检测不到的、紧急的、有操作性的,并且即将发生或者已经发生的用户可见故障
  • 是否可以忽略这条告警?什么情况可能会导致用户忽略这条告警,如何避免?
  • 这条告警是否确实显示了用户正在受到的影响?是否存在用户受到影响也可以触发这条规则的情况?
  • 收到告警后,是否需要进行某个操作?是否需要立即执行,还是可以等到第二天执行?操作是否可以自动化?操作是长期的还是短期的?
  • 是否也会有其他人收到告警,这些告警是否是不必要的?




监控系统的长期维护

关于监控系统的涉及决策应该充分考虑到长期目标。今天发出的紧急警报都会占用优化系统的时间,所以经常会牺牲一些短期内的可用性和性能问题,以换取未来系统性能的整体提升。








Google的自动化系统的演进

对于SRE而言,自动化是一种力量倍增器,而不是万能药。草率地进行自动化可能在解决问题的同时产生出其它问题。一个自治的系统。


自动化的价值

一致性

手动执行任务的方式对于整个组织和实际执行的人都不好。没有几个人能像机器一样永远保持一致,这不可避免的不一致性会导致错误、疏漏等问题。

在这个范畴内,一致性地执行范围明确、步骤已知的程序,是自动化的首要价值。




平台性

通过正确地设计和实现,自动化的系统可以提供一个可以扩展的、广泛适用的,甚至可能带来额外收益的平台。

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




修复速度更快

如果自动化能够始终成功运行,那么就可以降低一些常见故障的平均修复时间。随后,用户可以把时间花在其它任务上,从而提高开发速度。

在行业内普遍认同的是,在产品生命周期中一个问题越晚被发现,修复代价越高。




行动速度更快

在在基础设施中,SRE自动化系统应用广泛。这是因为人类通常不像机器一样快速反应。




节省时间

工程师对于一个特定的自动化或代码是否值得编写而摇摆不定,不停地比较写该代码所需要花费的精力与不需要手动完成任务所节省的精力。

这里很容易忽略一个事实,一旦你用自动化封装了某个任务,任何人都可以执行它们。因此,时间的节省适用于该自动化用的所有人。

将某个操作与具体操作的人解耦合是很有效的。




自动化对Google SRE的价值

当然,尽管Google在思想上倾向于尽可能使用机器管理机器,但实际情况需要一定的变通。将每个系统的每个组件都自动化是不合适的,同时不是所有人都有能力或倾向于在一个特定的事件开发自动化系统。




自动化的应用案例

广泛使用的工具有Puppet、Chef、Ansible,甚至Perl都提供了完成特定任务的方法,主要却别在于对帮助进行自动化的组件的抽象层次不通。

拥抱失败,承认故障是不可避免的,并通过自动化进行快速恢复。

节省的时间越多,优化和自动化其它繁琐工作的时间就越多。

自动化应该对那些隐含的安全信号非常小心。








发布工程

Release Engineering

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

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

SRE关注从源代码到部署的整个流程。




发布工程师的角色

负责产品更新的安全部署过程,保障这些服务可以正常运行。




发布工程学

  • 自服务模型
  • 追求速度
  • 密闭性
  • 强调策略和流程


为了应对大规模的扩张,每个团队必须能够自给自足。

越快上线越好。

构建工具必须确保一致性和可重复性。

多层安全和访问控制机制可以确保在发布过程中只有指定的人才能执行指定操作。




持续构建和部署

  • 构建
  • 分支
  • 测试
  • 打包
  • 部署


善用PR。

一个持续测试系统会在每个主分支改动提交之后运行单元测试,这样我们可以快速检测构建错误和测试错误。

每个包有固定名称,记录构建结果的哈希值,并且会加入签名以确保真实完整性。




配置管理

  • 将配置文件与二进制文件打包在一起
  • 从外部服务中读取配置文件








简单化

对于大多数生产环境软件系统来说,我们想要在稳定性和灵活想上保持平衡。

对于软件而言,乏味实际上是非常正面的态度。与侦探小说不同,缺少刺激、悬念和困惑是源代码的理想特性。生产环境中的意外时SRE最大的敌人。

为了减少意外复杂度,SRE团队应该:

  • 在他们所负责的系统中引入意外复杂度时,及时提出抗议
  • 不断地努力消除正在接手的和已经负责运维的系统的复杂度

SRE推送保证所有的代码都有必须存在的目的的实践。审查代码以确保它确实符合商业目标,定期删除无用代码,并且在各级测试中增加代码膨胀检测。

臃肿的软件直观上来看就是不可取的。删除没用的代码。

书写一个明确的、最小的API是管理软件系统简单性的必要的部分。

在API与单个二进制文件以外,适用于面向对象编程的许多经验法则也适用于分布式系统的设计。在各种二进制和配置文件之间推行松耦合,是一种同时提高开发人员的灵活性和系统的稳定性的简化模式。

随着系统变得越来越负责,API与二进制文件之间的责任分离变得越来越重要。

正如普遍认同的,编写一个其中包含无关功能的大杂烩是一个糟糕的实践。一个设计良好的分布式系统是由一系列合作者组成的,每一个合作者都具有明确的、良好定义的范围。

简单的发布流程总的来说要比复杂的发布流程更好。

软件的简单性是可靠性的前提条件。








具体实践

简单来说,SRE的职责是运维一个服务,该服务由一些相关的系统组件组成。SRE的终极责任是确保该服务可以正常运转。为了完成这个目标,SRE需要完成以下工作:开发监控系统、规划容量,处理紧急事件,确保事故根源被跟踪修复等。

鉴于此,我们可以将一个服务的监控程序指标分为——低级需求:能够正常对外提供服务;高级需求:SRE能够主动控制服务状态,而不是被动救火。

离开了监控系统,我们就没有能力辨别一个服务是不是在正常提供服务。没有一套设计周全的监控体系就如同蒙着眼睛狂奔。作为一个合格个运维,我们需要在用户之前发现系统中存在的问题。

SRE并不是为了on-call值班而值班,on-call只是我们实现服务目标的一种工具。如果找到一种方式使得值班不在必要,SRE肯定会第一时间采用。

在应急事件处理中,由于压力很大,很多情况下人们急于解决问题,会绕开必要的流程。

如何建立起无指责、对事不对人的团队文化。

事故追踪系统,跟踪最近发生的生产事故、原因以及解决的具体过程。

当我们发现经常出现问题的组件或流程时,下一步就是如何避免它再次发生故障。通过增加测试,保证不会出现类似问题。

服务容量规划。

Google SRE一半的精力都花在设计和开发大规模软件系统上。

产品设计理念位于金字塔顶端。








告警

基于时间序列数据进行有效告警

监控,处于整个生产环境需求金字塔模型的最底层。监控是运营一个可靠的稳定服务不可缺少的部分。服务运维人员需要依靠监控数据对服务的情况做出理性判断,用科学的方法应对紧急情况。同时,监控数据也可以用来确保服务质量与产品目标保持一致。

监控一个大型系统本身是以像非常具有挑战性的工作:

  • 大型系统中组件数量特别多,分析工作纷杂繁重
  • 监控系统本身的维护要求非常低

一个大型系统不应该要求运维人员持续关注其中使用的无数个小组件,而是因该自动汇总所有的信息,自动抛弃其中的异常情况。监控系统应该主要从高级服务质量目标层面进行报警,但是也应该保持足够的粒度,可以追踪到某个具体的组件。

这个模型将收集时间序列信息作为监控系统的首要任务,同时发展了一种丰富的时间序列信息操作语言。这就是Google的Borgmon监控系统,类似的还有Prometheus。


Borgmon将所有数据保存在一个内存数据库中,定时保存到硬盘上。这些数据都是以类似(timestamp, value)的格式存储在一个按时间排序的链表里,该链表称为时序(time-series)。同时,每个时序链表用一组唯一的标签命名(name=value)。

一个时序链表实际上是一个单维数字矩阵,以时间为Y轴。当给时序加上各种标签时,这个矩阵就变成多维矩阵了。

在实际实现中,这个数据接口存放在固定大小的内存块中。存放区满后,同时有一个垃圾回收器,将过期的数据从内存中清除。它会定时将内存状态归档到外部时序数据库(TSDB)。

Borgmon,每个数据点大概占用24Bytes的内存,存放100万个时序,每个时序每分钟一个数据点,同时保存12小时的数据,仅需17GB内存。


时序是按照时间戳和值的序列存放的,称之为向量(vector)。就像线性代数中的向量一样,这些向量是一个存放在时序存放区中的多维矩阵中的某一列,或某一个对角线数值串。

时序的名字称为标签集合(labelset),因为它的实现方式就是一个标签(key=value)的集合。

每个SRE团队都会将严重情况报警发送给当前on-call工程师。将重要但不紧急的报警发送给工单系统。其它报警一般用来作为历史数据或者服务监控台展示使用。


Borgmon是一个白盒监控系统,负责监控目标和服务的内部状态。

但是,白盒监控并不能完全代表一个被监控系统的所有状态。完全依赖白盒监控,意味着我们并不知道最终用户看到的是什么样。

例如,白盒监控只能看到已经接收到的请求,并不能看到由于DNS故障导致没有发送成功的请求,或者由于软件服务器奔溃而没有返回的错误。同时,报警策略也只包含了工程师能想到的错误情况。

Google SRE团队通常利用探针程序(prober)解决该问题,也就是云厂商的站点监控功能(tcp, udp, icmp, http…)。








on-call轮值

on-call轮值是很多运维和研发团队的重要职责,目标是保障服务的可靠性和可用性。但如果没有正确执行,将会给服务甚至团队带来非常严重的后果。

Google SRE和纯运维团队不同,SRE团队强调用工程化手段来应对运维问题。而这些运维问题,当达到一定规模时,也确实只有采用工程化手段才能解决。所以SRE 都是50%研发,50%运维。

一旦接收到报警消息,工程师必须确认,on-call工程师必须能够及时定位问题,并且尝试解决问题。必要的话,还可以联系其它团队。

多地团队有以下优势:

  • 长时间执行夜间任务对人健康不利。多地团队可以利用日出而作,日落而息的轮值制度使整个团队避免夜间值班
  • 通过限制一个团队在on-call轮值制度中的人员数量,可保障每个工程师对生产环境的熟悉程度

出现问题后,应该编写事故报告,仔细评估哪些地方有问题,哪些地方做的好是非常关键的。事故出现太多,超过了具体指标,那么管理团队必须采取一些修正措施保证运维压力下降到可持续水平。

管理层需要考虑,针对工作时间之外的on-call工作应该与合理的补贴。Google提供年假或现金补贴。同时应避免过量on-call带来的问题,如项目开发时间不够,或疲脑过度。


现代理论研究指出,在面临跳转时,一个人会主动或非主动(潜意识)低选择下列两种处理方法之一:

  • 依赖直觉,自动化、快速型到
  • 理性、专注、有意识地进行认知类活动

当处理复杂系统问题时,第二种行事方式更好。为了确保这样,必须要减轻on-call所带来的压力感。业务系统的重要性和操作所带来的影响程度会对on-call工程师造成巨大的精神压力,危害工程师的身体健康,并且可能导致SRE在处理问题过程中犯错误,从而影响到这个系统的可靠性。

在这些压力的影响下,on-call工程师往往会选择反应性的、未经详细考虑过的操作,并容易导致过度联想现象的产生。过度联想是on-call非常容易产生的现象。如on-call工程师收到本周内第四个同样报警信息时,很容易联想起前3次报警都是由于某个外部系统造成的虚假报警,于是很自然地将第4次报警也归类为虚假报警,从而没有认真处理,导致真实事故的发生。

在应急事故处理过程中,凭直觉操作和快速反应(如出现问题就先重启服务器)看起来都是很有用的方法,但是这些方法都有自己的缺点。直觉很可能是错误的,而且直觉一般都不是基于明确的数据支持的。因此,在处理问题的过程中,on-call工程师很有可能由于凭直觉去解释问题产生的原因而浪费宝贵的时间。快速反应主要是由习惯而产生的,习惯性的快速反应的动作后果一般都没有经过详细考虑,这可能会将灾难扩大。

在应急事件处理过程中,最理想的方法论应该这样:在有足够数据支撑的时候按步骤解决问题,同时不停地审视和验证目前所有的假设。

让on-call SRE知道他们可以寻求外部帮助,对减轻on-call压力也很有帮助。最重要的资源有:

  • 清晰的问题升级路线
  • 清晰定义的应急事件处理步骤
  • 无指责、对事不对人的文化氛围

对于操作生产环境,自信心太强以及自信心不足,都不是很好。








故障排查手段

系统正常,只是该系统无数异常情况下的一种特例。

故障排查是运维分布式计算系统的一项关键技能。

从理论上讲,我们将故障排查过程定义为反复采用假设-排除手段的过程。

有很多方法可以简化和加速故障排查过程。可能最基本的是:

  • 增加可观察性。在实现之初就给每个组件增加白盒监控指标和结构化日志
  • 利用成熟的、观察性好的组件接口设计系统








紧急事件响应

不管一个组织有多大,做的事情有多么重要,它最明显的特质就是:在紧急事件来临时人们如何应对。

当系统出现问题时,别惊慌失措!这不是世界末日,你也不是一个人在战斗!如果你感到自己难以应付,就去找更多人参与进来。

Google经常主动进行灾难处理和应急响应演习。事故响应和事故总结。

为事故保留记录,历史就是学习其他人曾经犯的错误。








紧急事故管理

有效的紧急事故管理是控制事故影响和迅速回复运营的关键因素。如果事先没有针对可能发生的紧急事故进行过演习,那么当事故发生时,一切管理理念都不起作用。


无流程管理的紧急事故

在上面所说的场景中,每个人都在尽力解决问题,起码在他们自己看来是这样。那么问题怎么变得越来越糟的呢?

有几个常见的问题导致了整个事故的失控:

  • 过于关注技术问题
  • 沟通不畅
  • 不请自来




紧急事故的流程管理要素

紧急事故流程管理的技巧和手段都是为了让这些富有热情的人能够真正帮上忙。

嵌入式职责分离:在事故处理中,让每个人清除自己的职责是非常重要的。

一些角色:

  • 事故总控
  • 事务处理团队
  • 发言人
  • 规划负责人


控制中心: 受到事故影响的部分或者人需要知道他们可以与事故总控负责人联系。


实时事故状态文档:该文档可以以wiki的形式存在,但是最好能够被多人同时编辑。


明确公开的职责交接。




流程良好的事故




什么时候对外宣布事故

先宣布事故发生,随后找到一个简单解决方案,然后宣布事故结束,要比在问题已经持续很久之后才想起流程管理更好。

应当针对事故设立一个明确的宣布条件:

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








事后总结

事后总结,从失败中学习。

学习是避免失败的最好办法。

一篇事后总结是一次事故的书面记录,包括该事故造成的影响,为缓解该事故采取的措施,事故的根本原因,以及防止未来事故重现的后续任务。




Google的事后总结哲学

在任何一个重要事故发生后,团队必须书写一份事后总结。要注意的是,书写事后总结不是一种惩罚措施,而是整个公司的一次学习机会。基本的事后总结条件:

  • 用户可见的宕机时间,或服务质量降级程序达到一定标准
  • 任何类型的数据丢失
  • on-call工程师需要人工接入的事故
  • 问题解决耗时超过一定限制
  • 监控问题

在SRE的文化中,最重要的就是事后总结对事不对人。一篇事后总结必须重点关注如何定位造成这次事件的根本问题,而不是指责某个人或某团队的错误或者不恰当的举动。如果因为某些错误的举动就公开指责或羞辱某个人或团队,那么人们就会自然地逃避事后总结。

避免职责,提供建设性意见。




协作和知识共享

不管采用哪些工具,请确保优先选择下列功能:

  • 实时协作
  • 开放的评论功能
  • 邮件通知








跟踪故障

提高可靠性的唯一可靠办法论是建立一个基线(baseline),同时不断跟踪改变。使用故障跟踪工具来做这些事。

将多个告警信息聚合成一个单独的故障能够有效解决这个问题,聚合功能能更好地消除重复告警,避免重复性工作。

对告警增加元数据信息(标签),更有效率。

汇总和分析一些历史告警数据。








测试可靠性

SRE的一项关键职责就是要定量地分析我们维护的某项服务的质量。


软件测试的类型

分为两类:

  • 传统测试: 主要用来在开发过程中离线评估软件的正确性
    • 单元测试
    • 集成测试
    • 系统测试
  • 生产测试: 评估一个已经部署的软件系统是否正常工作
    • 黑盒测试
    • 压力测试
    • 金丝雀测试




创造一个构建和测试环境




大规模测试

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








SRE部门中的软件工程实践

总体来说,SRE开发的工具是一个完整的软件工程项目,而不是一次性的脚本和小补丁。开发这些工具的SRE也需要针对内部用户的需求进行产品规划,指定未来的发展方向。




为什么软件工程对SRE很重要

SRE组织的一个指导思想是,团队大小不应该与用户服务规模成比例增长。在用户服务成指数增长的情况下,想要保持SRE团队以线性增长需要不断地进行自动化工具的开发,以及不停地优化工具、流程,消除一切其它日常运维相关的效率问题。

完整的软件工程项目在SRE组织内部提供了一个职业发展的方向,也提供了一些磨练编程技能的良好机会。




在SRE团队中培养软件工程风气








前端服务器的负载均衡

运维大型系统时,将所有鸡蛋放在一个篮子里是引来灾难的最好办法。




有时候硬件并不能解决问题

一台无穷大配置的机器,传输速度也会有限制,而且存在单点故障。

一个搜索请求和一个视频上传请求。用户想要快速的获取搜索结果,所以对搜索请求来说最重要的变量是延迟(latency)。而对于视频上传请求来说,最重要的变量是吞吐量(throughput)。两种请求用户的需求不同,是我们在全局层面决定最优分配方案的重要条件。

  • 搜索请求将会被发送到最近的可用数据中心
  • 视频上传需要寻找一条带宽没有占满的链路,这可能会牺牲一定程度的延迟

但是在局部层面,在一个数据中心内部,网往关注与优化资源的利用率,避免某个服务器负载过高。




使用DNS进行负载均衡

CDN其实也就是就近原则(最优位置)的DNS负载均衡。




虚拟IP

虚拟IP(VIP)不是绑定到某一个特定的网络接口上,它是由很多设备共享的。








数据中心内部的负载均衡系统

理想情况下,某个服务的负载会完全均匀地分发给所有的后端服务。


异常任务的简单应对方法: 流速控制。

一个可靠的识别异常任务的方法: 跛脚鸭状态(后端任务正在监听端口,并且可以服务请求,但是已经明确要求客户端停止发送请求)。

利用划分子集限制连接池大小。


负载均衡策略:

  • 简单轮询算法
  • 最闲轮询算法
  • 加权轮询策略








应对过载

避免过载,是负载均衡策略的一个重要目标。但无论负载均衡策略效率有多高,随着压力的上升,系统的某个部位总会过载。运维一个可靠系统的一个根本要求,就是能够优雅地处理过载情况。

无论如何,构建良好处理资源限制的客户端和对应的后端服务是最好的。在可能的情况下重定向请求,在必要时返回降级回复,同时在最差情况下,能够妥善地处理资源受限导致的错误。




QPS陷阱

不同的请求可能需要数量迥异的资源来处理。某个请求的成本可能由各种各样的因素决定。

Google在多年的经验积累中得出,按照QPS来规划服务容量,或按照某种静态属性一般是错误的选择。

更好的解决方案是直接以可用资源来衡量可用容量。简单地使用CPU和MEM作为资源配给的主要信号就可以工作的很好。




给每个用户设置限制

过载应对策略设计的一部分是决定如何处理 全局过载(global overload) 的情况。在理想情况下,每个团队能和他们所依赖的后端服务团队直接协调功能发布,从而使后端服务永远有足够容量服务最终用户,这样全局过载就不会发生。不幸的是,现实总是很残酷。全局过载情况在实际运行中出现得非常频繁。

当全局过载发生时,使服务只针对某些异常客户返回错误是非常关键的,这样其他用户则不会受影响。为了达到这个目的,该服务的运维团队和客户团队协商一些合理的使用约定,同时使用这个约定类配置用户配额,并且配置相应的资源。




客户端侧的节流机制

有时候,可能拒绝请求、发送拒绝回复仍然会消耗一定数量的资源。如果回复数量很多,这些消耗可能也十分客观。这种情况,有可能也会让后端服务过载。

客户端侧的节流机制可以解决这个问题。客户端直接本地回复失败,而不会真正发送到网络层。




重要性

  • 最重要
  • 重要
  • 可丢弃




资源利用率信号

我们的任务过载保护是基于资源利用率(使用量除以预留量)实现的。




处理过载错误