Google SRE ——拥抱风险
更新时间: 2016-10-17 00:16
前言
你可能曾经期望 Google 试图构建一个百分之百可靠的服务。事实证明,超过一定值 后,再提高可靠性对于一项服务(和它的用户)来说,结果可能会更差而不是更好!极 端的可靠性会带来成本提升 :最大程度地提高稳定性限制了新功能的开发速度和将产品 交付给用户的速度,并且很大程度地增加了成本,这反过来又减少了一个团队可以提供的新功能的数量。
此外,用户通常不会注意到一项服务高可靠性和极端可靠性之间的差 异,因为用户体验主要是受较不可靠的组件主导。
例如 手机移动网络或者他们正在使用 的设备。简单地说,用户在一个有着 99% 可靠性的智能手机上是不能分辨出 99.99% 和 99.999% 的服务可靠性的区别的!
基于这一点,网站可靠性工程师旨在寻求快速创新和高效的服务运营业务之间的风险的平衡,而不是简单地将服务在线时间最大化。这样一来,我们可以优化用户的整体幸福感, 以及系统的功能、服务和性能。
管理风险
不可靠的系统会很快侵蚀用户的信心,所以我们想要减少系统故障的几率。然而,经验表明,在构建系统的过程中,可靠性进一步提升的成本并不是线性增加的——可靠性的下一个改进可能比之前的改进成本增加 100 倍。高昂的成本主要存在于以下两个维度。
-
冗余物理服务器 / 计算资源的成本
通过在冗余设备上花费成本,可以允许我们进行常规的系统离线或其他不可预见的维护性操作。又或者可以提供一些空间来存储奇偶校验码块,以此来提供最低的数 据持久性保证。 -
机会成本 这类成本由某一个组织承担。当该组织分配工程资源来构建减少风险的系统或功能, 而非那些用户直接可用的功能时需要承担这些成本。这些工程师不再从事为终端用 户设计新功能和新产品的工作。
在 SRE 团队中,我们管理服务的可靠性很大程度上是通过管理风险来进行的。我们将风 险作为一个连续体来认知。对于提高 Google 系统的可靠性和对服务故障的耐受水平,我 们给予了同样程度的关注。这样做可以让我们通过进行成本/收益分析。
例如 Search、Ads、Gmail 或者Photos应该被放置在风险连续体上(非线性)的那一点。我们的目标是明确将运维风险与业务风险对应起来。我们会努力提高一项服务的可靠性,但不会超 过该服务需要的可靠性。
也就是说,当设定了一个可用性目标为 99.99% 时,我们想要 超过这个目标,但不会超过太多 :这样会浪费为系统增加新功能、清理技术债务或者降 低运营成本的机会。从某种意义上来说,我们把可用性目标同时看作风险的最小值和最 大值。这种表达方式的主要优势是,它可以促使团队进行明确的、深思熟虑的风险讨论。
度量服务的风险
作为 Google 标准的做法,我们往往通过确定一个客观的指标来体现一个想要优化的系统 属性。通过设立一个目标,我们可以评价目前的系统表现以及追踪一段时间内的改进和 退步。
对于服务风险而言,如何将所有的潜在因素缩减为一个单一的性能指标,可能不 是一件能够立刻解决的事情。服务故障可能会有很多潜在的影响,包括用户的不满、伤害, 或丧失信任;直接或者间接的收入损失;品牌以及口碑上的影响;还有不良的新闻报道等。 很明显,这些因素中的一部分很难被合理地度量。
为了使这个问题在我们运行的各种类型的系统中易于处理,并且保持一致性,我们会关注于计划外停机这个指标。对于大多数服务而言,最直接的能够代表风险承受能力的指标就是对于计划外停机时间 的可接受水平。
计划外停机时间是由服务预期的可用性水平所展现的,通常是用我们愿 意提供的“9”系列的数字来体现的,比如可用性为 99.9%、99.99% 或 99.999%。
每个 额外的“9”都对应一个向 100% 可用性的数量级上的提高。对于服务系统而言,这个指标通常是基于系统正常运行时间比例的计算得出的公式1。
公式1:基于时间的可用性
可用性=系统正常运行时间/(系统正常运行时间+停机时间)
使用这个公式,我们可以计算出一年内可接受的停机时间,从而可以使可用性达到预期 目标。举例来说,一个可用性目标为 99.99% 的系统能最多在一年中停机 52.56 分钟,就可以达到预计的可用性目标。
然而,在 Google 内部,基于时间的可用性通常是毫无意义的。因为我们需要着眼全球 范围内的分布式服务。采用故障隔离的方法使得我们能够在任何时候、任何地方对于一 个给定的服务,至少可以处理一部分用户流量。(也就是说,我们随时都是部分“在线” 的)。
因此,我们通过请求成功率来定义服务可用性。公式2 体现了这个基于产量的指 标是怎样通过滚动窗口计算出来的(比如,一天内成功请求的比率)。
公式2:合计可用性
可用性=成功请求数/总的请求数例如 一个每天可用性目标为 99.99%的系统,一天要接受 2.5M 个请求。它可以在每天出现 250 个错误的同时仍然达到预计的可用性目标。
在一个典型的应用中,不是所有的请求都是平等的:一个新的用户注册请求失败和一个 对于背景中的新邮件的轮询请求失败是不同的。
然而在许多情况下,从终端用户的角度 来看,通过计算全部请求成功率是一个对于计划外停机时间的合理估计。
使用请求成功率指标量化计划外停机时间使得这种指标更适合在不直接服务终端用户的 系统中使用。大多数非服务性的系统(比如,批处理、流水线、存储服务以及交易系统等)对成功和非成功的工作单元有明确的定义。
事实上,虽然在本章中讨论的系统基本上都是有关消费者类型和基础设施服务类型的系统,但是同样的原则也基本上适用于非服务 型的系统。
例如 一个批处理进程通过提取、转换,并将客户数据库中的一位客户的数据内容插入 到数据仓库中,以便进行定期的进一步分析。通过使用某条记录处理成功和处理不成功来定义请求成功率,我们能计算出一个有效的可用性指标,尽管事实上该批处理系统并 不是持续运行的。
通常,我们会为一项服务设定季度性的可用性目标,并且每周甚至每天对性能进行跟踪。
这个策略使我们通过寻找、跟踪和调整重要的、不可避免的偏差来使服务达到一个高层 次的可用性目标。
服务风险容忍度
辨别服务的风险容忍度是指什么?在一个正式的环境或安全关键的系统中,服务的风险容忍度通常是直接根据基本产品或服务的定义建立的。在 Google,服务风险容忍度却往 往定义得没有那么清楚。
为了辨别服务的风险容忍度,SRE 必须与产品负责人一起努力将一组商业目标转化为明 确的可以实现的工程目标。在这种情况下,我们所关心的商业目标会直接影响所提供服 务的性能和可靠性目标。
在实践中,这种转化说起来比做起来要容易得多。消费者类型 的服务往往有明确的产品负责人,而对于基础设施服务来说,拥有类似的产品所有权结 构是很少见的(例如,存储系统或者通用的 HTTP 缓存层)。接下来,我们会依次讨论消费者服务和基础设施服务。
辨别消费者服务的风险容忍度
我们的消费者服务通常会有一个产品团队,作为一个应用程序的商业所有者。比如说, Search、Google Maps 和 Google Docs 它们每一个都有自己的产品经理。这些产品经理负 责了解用户和业务,并负责在市场上成功地塑造产品的定位。
存在产品团队时,我们能 够更好地通过它来讨论服务的可靠性要求。在没有专门的产品团队的情况下,建立系统 的工程师们经常在知情或不知情的情况下扮演这个角色。
评价服务风险容忍度时,有许多需要考虑的因素。如下 :
-
需要的可用性水平是什么?
-
不同类型的失败对服务有不同的影响吗?
-
我们如何使用服务成本来帮助在风险曲线上定位这个服务?
-
有哪些其他重要的服务指标需要考虑?
可用性目标水平
对于某个 Google 服务而言,服务的可用性目标水平通常取决于它提供的功能,以及这项服务在市场上是如何定位的。下面列出了要考虑的一些问题 :
-
用户期望的服务水平是多少?
-
这项服务是否直接关系到收入(我们的收入或我们的客户的收入)?
-
这是一个有偿服务,还是免费服务?
-
如果市场上有竞争对手,那些竞争对手提供的服务水平如何?
-
这项服务是针对消费者还是企业?
例如 Google Apps for Work,这个服务的主要用户是企业类用户,包括大型企业和中 小企业。这些企业依靠谷歌应用程序提供的办公类型的服务(例如 Gmail、Calendar、 Drive和Docs)让员工进行日常工作。另一方面,一个Google Apps for Work服务的中断不仅会影响 Google 本身,也会影响到那些在业务上非常依赖于我们的企业。
对于这 类服务,我们可能会设置一个季度性的外部可用性目标为 99.9%。同时,我们会设置一 个更高的内部可用性目标,以及签署一份如果我们未能达到外部目标的处罚性协议。
YouTube 则需要截然不同的考虑。当 Google 收购 YouTube 后,我们需要为该网站提供 一个更恰当的可用性目标。2006 年 YouTube 比当时的 Google 更加专注于消费者并且当 时处于一个与 Google 非常不同的企业生命周期阶段。
尽管 YouTube 已经有了一个出色 的产品,它仍然在不断变化和快速发展着。我们为 YouTube 设定一个相比我们企业的产 品更低的可用性目标,因为快速发展更加重要一些。
故障的类型
对于一项给定的服务的故障预期状态是另一个重要的考虑因素。我们的业务对于服务的停机时间容忍程度有多高?持续的低故障率或者偶尔发生的全网中断哪一个会更糟糕?
这两种类型的故障可能会导致绝对数量上完全相同的错误被返回,但可能对于业务的影 响相差很大。
下面这个例子是一个提供私人信息的系统中自然发生的完全和部分服务中断的区别。
假设,一个联系人管理应用程序,一个是导致用户头像显示失败的间歇性故障,另外一个 是将 A 用户的私人联系列表显示给 B 用户的故障。
第一种情况显然是一个糟糕的用户体 验,SRE 会努力去快速地解决问题。
然而,在第二种情况下,暴露私人数据的风险可能会破坏基本的用户信任。因此,在第二种情况下,在进行调试和事后的数据清理时,完 全停止该服务更加恰当。
对于 Google 提供的其他服务,有的时候,我们可以接受计划内的常规的服务中断。
几年前, Ads Frontend 曾经就是这样的一种服务。它是广告商和网站创建者用来建立、配置、运行和监控他们的广告活动的服务。因为这项工作大部分发生在正常工作时间,我们认为那些维修窗口中出现的偶然的、正常的、计划之中的中断是可以接受的,并且我们把这些计划中的中断看作计划内停机时间,而不是计划外停机时间。
成本
决定一项服务的合理可用性目标时,成本通常是很重要的因素。
Ads 就能很好地体现出这种权衡,因为成功与失败直接通过赢利和亏损体现。再为每一 项服务确定可用性目标时,可以问如下的问题 :
-
如果我们想要创建和运营一个可用性再多一个“9”的系统,我们的收益会增加多少?
-
这个额外的收入是否能够抵消为了达到这一水平可靠性所付出的成本?
为了使这个权衡等式更精确,假设一项业务中每一个请求都等值,考虑如下的成本或者
收益:
-
建议改进可用性目标 :99.9% → 99.99%
-
建议增加的可用性 :0.09%
-
服务收入 :100 万美元
-
改进可用性后的价值 :100 万美元 ×0.0009 = 900 美元
在这种情况下,如果提高可用性的一个“9”的成本是不到 900 美元,这是合理的投资。但是, 如果成本超过 900 美元,那么成本将超过预计增加的收入。
当我们不能简单地解释可靠性和收入的关系的时候,可能会更难设置这些目标。这时, 考虑在互联网中 ISP 的背景误差率可能是个不错的实用策略。如果从最终用户的角度测算故障,那么让服务的失误率低于背景失误率就是可能的。
这些失误将归入给定用户的互联网连接的噪声当中。虽然 ISP 和协议之间存在明显差异(比如,TCP vs UDP、IPv4 vs IPv6),但是我们测算的 ISP 的背景误差率已经下降至 0.01% 和 1% 之间。
其他服务指标
通过指标来检查服务的风险容忍度,除了可用性,其他指标也通常是很有效的。了解哪些指标是重要的,哪些指标是不重要的,可以为我们在试图承受风险时提供了空间。
我们广告系统的服务延迟提供了一个具有说服力的例子。当谷歌首先推出Web Search时, 一个很关键的特点就是速度。当我们提到 AdWords 时,它就是将广告显示在搜索结果旁 边。这个系统的一个关键要求就是广告不能拖累用户的搜索体验。这个要求是作为每一 代的 AdWords 系统创建的一个不变的目标。
AdSense, 作为 Google 的广告系统为了满足出版商将 JavaScript 代码插入到自己的网站中的要求提供上下文广告,有一个非常不同的延迟目标。对于 AdSense 而言,延迟的目标 是避免在插入上下文广告时影响到第三方页面。这个特定的延迟目标是依赖于给定的发 布者的页面呈现的速度。这意味着 AdSense 的广告一般要比 AdWords 的广告慢数百毫秒。
这种宽松的服务延迟要求允许我们在供应的时候能够做出一些明智的权衡(比如,决定 我们使用的服务资源的数量和位置),这能够帮我们减少单纯供应商的大量成本。换句话说,相对不敏感的 AdSense 服务的延迟表现变化平缓,使得我们能够整合服务较少的 地理区域来减少业务开销。
辨别基础设施服务的风险容忍度
创建和运行基础设施组件的要求在许多方面是不同于对消费产品的要求的。根据定义, 一个根本的区别就是,基础设施组件有多个客户,他们通常有很多不同的需求。
可用性目标水平
Bigtable 是一个大型结构化数据的分布式存储系统。一些消费者服务的服务数据直接通 过一个用户请求的路径提供。
这样的服务需要较少的延迟和较高的可靠性。其他团队把 Bigtable 看作数据的存储库,这样就可以定期进行离线分析(例如,Map Reduce)。这些 团队往往更关注业务量而不是可靠性。这两个情况的风险容忍度相当不同。
能够同时满足两种情况的要求的一种方法就是所有基础设施服务都是极可靠的。实际上,这些基础设施服务还倾向于聚集大量的资源,因此这样的做法在实践中通常是非常昂贵的。为了了解不同类型用户的不同需求,你可以看看每种类型的 Bigtable 的用户请求队 列的期望状态。
故障类型
低延迟的用户希望 Bigtable 的请求队列(几乎总是)为空,这样的话系统可以立刻处理 每个出现的请求。(事实上,效率低下的排队往往是导致较高的长尾延迟的原因。)考虑 离线分析的用户更感兴趣的是系统的吞吐量,因此用户希望请求队列永远不为空。为了优化吞吐量,Bigtable 系统在等待它的下一个请求时应该不需要空闲。
如你所见,对于这些用户而言成功和失败是相反的。低延迟用户的成功是关注离线分析的用户的失败。
成本
在符合成本效益条件下能够满足这些竞争性约束的方式就是将基础设施分割,并在多个 独立的服务水平上提供基础设施服务。
在Bigtable 的例子中,我们能够构建两个集群:低延迟集群和业务量集群。低延迟集群 是为运营那些需要延迟率较低和可靠性较高的服务而设计的。为了确保缩短队列的长度 和满足更严格的客户端隔离要求,减少竞争和增加冗余而形成的大量闲置能力可以提供 给Bigtable系统。
另一方面,业务量集群可以run very hot并且减少延迟,在延迟方面优化业务量。实际工作中,我们能以一个很低的成本来满足这些需求,大概只有低延迟 集群成本的 10%~50%。
由于 Bigtable 规模较大,所以成本节约也就变得愈发重要了。基础设施建设的关键战略就是通过明确划定的服务水平来提供服务,从而使客户在构建系统时能够进行正确的风险和成本权衡。通过明确划定的服务水平,基础设施供应商可以有效地体现出在给定程 度范围内向用户提供服务的成本中的差异。
以这种方式暴露成本可以促使客户选择既能够满足他们的需求又能够压缩成本的服务水 平。例如,Google+ 决定把数据放在一个至关重要的位置上,在一个可用性高、全球统一的数据存储中来保证用户的隐私。(例如,一个全球复制式的类似于 SQL 的系统,如Spanner),然而把可选数据(不重要的数据,但是能够增加用户体验) 放在一个价格更低、可靠性更低、更没经验的和最终一致的数据存储(例如,a NoSQL store with best-effort replication like Bigtable)
我们可以使用相同的硬件和软件运行多个类别的服务。可以通过调整各种服务特性提供 不同的服务保障,如资源的数量、冗余程度、地理配置的约束,还有很重要的基础设施 软件配置。
举例:前端基础设施
为了解释这些风险容忍度评估原则不适用于存储基础设施,我们再看一下另一大类型的 服务:Google的前端基础设施。这个前端基础设施是由反向代理和运行临近网络边缘的 负载平衡系统组成的。
这些就是作为连接终端用户的一个端点来服务的系统(例如,在用户的浏览器中终止 TCP)。由于它们所扮演的关键角色,我们通过设计这些系统来表现超高水平的可靠性, 而面向消费者的服务往往要在后台限制对于不可靠性的可见程度,这样的基础设施因此 也就没那么幸运了。如果一项请求没有到达应用服务的前端服务器,那么就意味着这项 请求丢失了。
我们已经探讨了识别消费者服务和基础设施服务风险耐受能力的方法。现在,我们将继 续讨论如何运用已知风险耐受水平来通过错误预算调整不可靠性。
总结
-
管理服务的可靠性主要取决于管理风险,而且管理风险价格非常昂贵。
-
100% 可能永远都不是一个正确的可靠性目标 :它不仅是不可能实现的,而且 它通常比一项服务的用户期望的可靠性要更多。我们要将服务产生的风险和企业愿意承担的风险相匹配。
-
误差估计调整会鼓励和重视 SRE 和产品开发之间的共同所有权。误差估计使
它更容易决定释放比率,能有效地恢复与利益相关者之间的沟通,并且能够 使多个团队毫无怨言地对于生产风险达成一致结论。