可靠性

本部分架构框架介绍如何应用技术和过程要求,以在 Google Cloud 上构建和运营可靠服务。

框架由以下系列文档组成:

可靠性对于任何应用而言都是最重要的特点,因为如果应用不可靠,用户最终会离开,而其他特性也就无关紧要了。

  • 应用必须具有可衡量的可靠性目标,并且必须及时纠正偏差。
  • 应用必须具有可扩缩性、高可用性并且可以自动化变更管理。
  • 应用必须尽可能自行修复,并且必须插桩以实现可观测性。
  • 用于运行应用的操作过程必须将运营人员的手动工作量和认知负担降到最低,同时确保快速缓解故障。

策略

使用以下策略来实现可靠性。

可靠性由用户定义。 对于面向用户的工作负载,您需要衡量用户体验(例如查询成功率),而不只是衡量 CPU 使用率等服务器指标。对于批量和流式工作负载,您可能需要衡量 KPI(关键绩效指标),例如每个时间窗口扫描的行数,以确保季度报告按时完成,而不只是衡量服务器指标,如磁盘使用率。

使用足够的可靠性。 您的系统应足够可靠以确保用户满意,但不能过于可靠以至投资不合理。定义设置可靠性阈值的服务等级目标 (SLO),并使用错误预算来管理变化率。仅在 SLO 与费用相符时才应用下面列出的其他原则。

创建冗余。 具有高可靠性需求的系统必须避免单点故障,并且必须在多个故障网域之间复制其资源。故障网域是可以单独出现故障的资源池,例如虚拟机、区域或地区。

加入横向可扩缩性。 添加更多资源,确保系统的每个组件都能适应流量或数据的增长。

确保过载承受能力。 设计服务,使其能在过载时平缓降级。

加入回滚能力。 运营人员对服务所做的任何更改都必须具有明确定义的撤消方法,即回滚更改。

防止流量高峰。 请不要跨客户端同步请求。太多客户端在同一时刻发送流量会导致流量高峰,最严重的情况下会导致级联故障。

测试故障恢复。 如果您近期未测试故障恢复操作流程,这些流程可能无法在需要时顺利执行。定期测试的内容包括地区故障转移、回滚到某个版本以及从备份恢复数据。

检测故障。 您需要在过早提醒导致运营团队疲于应付与过晚提醒导致服务中断延长之间进行权衡。在通知运营人员服务中断之前的延迟时间(也称为 TTD:检测时间)必须根据这种权衡进行调整。

进行增量更改。 对服务二进制文件或配置进行的即时全局更改本身就存在风险。我们建议您逐步发布更改,通过“Canary 测试”在发布早期阶段检测 bug,因为这个阶段的 bug 对用户的影响是最小的。

使用协调一致的紧急响应方式。 运营方式的设计应尽量缩短中断持续时间(也称为 TTM:缓解时间),同时兼顾客户体验和运营人员的负担。此方法要求使用明确定义的角色和沟通渠道提前规范化响应过程。

使用插桩系统实现可观测性。 系统必须经过充分插桩,以实现快速分类、问题排查和诊断,从而最大限度地减少 TTM。

记录并自动化紧急响应。 在紧急情况下,人们很难明确地决定需要完成的工作并执行复杂的任务。因此,请提前规划好紧急操作并记录下来,最好能够将其自动化。

执行容量管理。 在峰值流量事件发生前预测流量和预配资源。

减少手动操作。 手动操作是指需要手动完成的重复性工作,这类工作没有持久的价值,并且工作量会随着服务的发展而增加。您应不断努力减少或消除费力的手动操作。否则,运营工作最终会给运营人员带来巨大的压力,几乎没有发展的空间。

最佳做法

请遵循以下最佳做法,以帮助实现可靠性。

  • 使用服务等级目标 (SLO) 和错误预算确定您的可靠性目标。
  • 将可观测性内置到您的基础架构和应用中。
  • 在设计时确保可扩缩性和高可用性。
  • 构建灵活的自动化部署功能。
  • 构建高效的提醒功能。
  • 构建突发事件管理协作流程。

确定您的可靠性目标

我们建议您衡量现有客户体验以及客户对错误的容忍度,以便根据这些事件确定可靠性目标。 比方说,在无限长的时间内实现 100% 的整体系统正常运行时间目标是无法实现的,而且如果用户期望的数据不存在,这样做也没有意义。

根据用户体验设置 SLO。尽可能靠近用户来衡量可靠性指标。如果可能,请对移动或 Web 客户端进行插桩。如果不可行,请对负载平衡器进行插桩。在服务器上衡量可靠性应作为最后的选择。将 SLO 设置到足够高以确保用户满意,但不可设置得过高。

由于网络连接或其他暂时性的客户端问题,客户可能会在短时间内遇到由您的应用引起的一些可靠性问题。

我们强烈建议您将正常运行时间和其他重要指标的目标设在 100% 以下,但是接近此值。此目标可让所有人更快速地提供更优质的软件。此外,在许多情况下,如果系统设计合理,您可以降低更改的速度和更改量来提高可用性。

换句话说,根据客户体验调整要实现的可靠性目标往往有助于确定客户可以接受的最大更改速度和范围(即功能速度)。

如果您无法衡量现有客户体验并据此确定目标,我们建议您进行竞争性基准分析。在缺少可比较的竞争关系时,即使您还无法确定目标(例如系统可用性或有意义且成功的客户交易率),也要衡量客户体验。您可以将其与业务指标或 KPI 关联,如订单量(零售)、客户服务电话和工单量及其严重程度等。在某些时候,您可以使用这样的关联来达到合理的客户满意度阈值,也就是 SLO。

SLI、SLO 和 SLA

“服务等级指标”(SLI) 是对所提供服务的等级的某些方面进行定量衡量的指标。它是一个指标,而非目标。

“服务等级目标”(SLO) 用于指定服务可靠性的目标等级。由于 SLO 是做出有关可靠性的数据驱动型决策的关键,因此它们是 SRE 做法的核心。SLO 是 SLI 的值,当 SLI 等于或超过此值时,该服务被视为“足够可靠”。

一段时间内“错误预算”的计算公式为 (100% – SLO)。此值可说明您的系统在某个时间窗口内是高于还是低于所需的可靠性。我们通常建议您使用 30 天的滚动窗口。

服务等级协议 (SLA) 是与您的用户签订的显式或隐式合同,其内容涵盖达成(或未达成)所包含的 SLO 的影响。

建议将内部 SLO 设置得比外部 SLA 更严格。采用这种做法的原因在于违反服务等级协议 (SLA) 往往要求您发放财务补偿或客户退款,而您希望在问题产生财务影响之前就着手解决。我们建议应用更严格的内部 SLO,建立突发事件审核机制,以执行无责备的事后分析流程。

如果应用采用多租户架构(多个独立客户使用的典型 SaaS 应用),请务必按租户级层捕获 SLI。如果您仅在全局汇总级层衡量 SLI,您的监控将无法标记影响单个客户或少数客户的关键问题。设计应用以在每个用户请求中包含租户标识符,并将该标识符传播到应用栈的每一层。通过传播此标识符,您的监控系统可以在请求路径中的每一层或微服务中汇总租户级层的统计信息。

错误预算

使用错误预算来管理开发速度。在错误预算尚未用尽时,您可以继续快速发布新功能。当错误预算接近零时,请冻结或减慢服务更改,并在可靠性特性方面投入工程资源。

Google Cloud 通过服务监控最大限度地减少了设置 SLO 和错误预算的工作量。 此产品提供了一个可手动配置 SLO 的界面、以程序化方式设置 SLO 的 API,以及用于跟踪错误预算使用率的内置信息中心。

示例 SLI

对于服务系统,通常采用以下 SLI:

  • 可用性反映服务可用时间所占的比例。它通常根据格式正确的成功请求来定义,例如 99%。
  • 延迟时间反映特定百分比的请求可以完成的速度。它通常用除第 50 百分位以外的百分位来定义,例如,第 99 百分位为 300 ms。
  • 质量反映特定响应的好坏程度。质量的定义通常是特定于服务的,用于指明对请求的响应内容与理想响应内容的差异程度。它可以用二进制数表示(好或差),也可以用 0% 到 100% 来表示。

对于数据处理系统,通常采用以下 SLI:

  • 覆盖率反映已处理的数据比例,例如 99.9%。
  • 正确率反映被视为正确的响应所占的比例,例如 99.99%。
  • 新鲜度反映源数据或汇总响应的新鲜程度,通常情况下新鲜度越高越好,例如 20 分钟。
  • 吞吐量反映正在处理的数据量,例如 500 MiB/秒甚至 1000 RPS。

对于存储系统,通常采用以下 SLI:

  • 耐用性反映写入系统的数据将来被检索的可能性,例如 99.9999%。任何数据永久丢失事件都会降低耐用性指标。
  • 吞吐量延迟时间(如前所述)。

设计问题

  • 您是否在衡量应用可靠性的用户体验?
  • 客户端应用的设计能否捕获和报告可靠性指标?
  • 系统架构在设计时是否考虑了特定的可靠性和可扩缩性目标?
  • 对于多租户系统,用户请求是否包含租户标识符,该标识符是否传播到软件栈的每一层?

建议

  • 定义并衡量以客户为中心的 SLI。
  • 定义比外部 SLA 更严格、以客户为中心的错误预算,该 SLA 应涵盖违规后果,例如生产冻结。
  • 设置延迟时间 SLI 以捕获离群值(即第 90 或第 99 百分位),以检测最慢响应。
  • 每年至少审核一次 SLO。

资源

将可观测性内置到您的基础架构和应用中

可观测性包括监控、日志记录、跟踪、性能剖析、调试和类似系统。

对代码进行插桩以最大限度地提高可观测性写入日志条目并跟踪条目,在考虑调试和问题排查的同时导出监控指标,对系统中最可能或最频繁出现的故障模式进行排序。 定期审核和删减监控,删除未使用或无用的信息中心、提醒、跟踪和日志记录,以免杂乱无章。

监控是服务可靠性层次结构的基础。如果没有适当的监控,您将无法在第一时间判断应用是否正常运行。

精心设计的系统的目标是从开发阶段开始就具有适当的可观测性。不要等到应用进入生产阶段才开始观测。

Google Cloud 的运维套件可跨 Google Cloud 和 AWS 提供实时监控、日志记录、跟踪、性能剖析和调试功能。它还能够使用 Istio 和 App Engine 服务 (Cloud Monitoring) 监控服务网格。

过度设计监控和过度提醒是常见的反模式。为避免这些反模式,请主动删除初始外部发布阶段未查看或很少触发的时间序列、信息中心和提醒。 这对于很少扫描的日志条目也有效。

评估将所有或一个示例应用事件发送到云数据仓库(如 BigQuery)的情况。这非常有用,因为它可以让您以较低的费用运行任意查询,而无需提前设计监控。它还可以将报告和监控分离开。任何人都可以使用 Google 数据洞察或 Looker 完成报告。

设计问题

  • 设计审核流程中是否有指导设计审核和代码审核的可观测性标准?
  • 应用导出的指标是否足以排查服务中断问题?
  • 应用日志条目是否足够详细且足够相关,以便进行调试?

建议

  • 在开始迁移之前实现监控,或在首次生产部署前构建新应用时实现监控。
  • 区别应用问题与底层云问题,例如使用透明 SLIGoogle Cloud 状态信息中心
  • 定义除性能剖析之外的可观测性策略,包括跟踪、性能剖析和调试。
  • 定期清理未使用或无用的可观测性工件,包括不可执行的提醒。
  • 将应用事件(即高基数指标)发送到 BigQuery 等数据仓库系统。

在设计时确保可扩缩性和高可用性

设计具有故障转移功能的多地区架构

如果您的服务在发生地区性故障时仍需要正常运行,请将其设计为使用分布在不同地区的计算资源池,使其具备在地区故障时自动进行故障转移的功能。消除单点故障,例如在无法访问时可能导致全球服务中断的单个地区主数据库。

消除可扩缩性瓶颈

识别无法超越单个虚拟机或单个区域资源限制的系统组件。一些应用专为纵向扩缩而设计,因此单个虚拟机需要更多 CPU 核心、内存或网络带宽以处理不断增加的负载。此类应用对可扩缩性有严格的限制,并且通常需要手动重新配置以处理增长。使用分片(跨虚拟机或区域进行分区)重新设计这些组件使其具备横向可扩缩性,以便通过添加更多分片轻松处理流量或使用量增长。分片使用标准虚拟机类型,可自动添加以处理每个分片的负载增长。作为重新设计的替代方案,您可以考虑将这些组件替换为无需用户操作即可横向扩缩的代管式服务。

平缓降低服务等级

设计您的服务以检测过载,并向用户返回降低质量的响应或减少部分流量,而不是在遇到过载时完全不能工作。例如,服务可以使用静态网页响应用户请求,同时暂时停用较昂贵的动态效果,或者允许在暂时停用数据更新时执行只读操作。

使用抖动实现指数退避算法

当移动客户端遇到来自服务的错误响应时,必须在随机延迟后重试。如果收到重复的错误,则其除了向每个重试操作添加随机时间偏移量(抖动)之外,还应在等待指数级时间之后重试。这样可以防止大量客户端在移动网络故障后生成即时流量峰值,因为这些峰值可能会导致您的服务器崩溃。

预测峰值流量事件并规划应对方法

如果您的系统遇到已知的流量高峰期(例如零售商的黑色星期五),请投入时间应对此类事件,以避免流量损失和收入损失。预测流量峰值的大小,增加缓冲区,并确保您的系统有足够的计算能力来处理高峰。使用预期的用户请求组合对系统进行负载测试,以确保其预估的负载处理能力与实际能力相符。在您的运营团队执行模拟中断演习时进行练习,重新排定其响应程序,并执行下面介绍的跨团队突发事件协作管理程序。

执行灾难恢复测试

不要等到灾难来袭再行动;请定期测试和验证您的灾难恢复程序和流程。 您可能还在规划可实现高可用性 (HA) 的架构。 它与灾难恢复 (DR) 并不完全重叠,但在考虑恢复时间目标 (RTO) 和恢复点目标 (RPO) 值时,通常需要考虑 HA。HA 有助于确保实现约定的运行表现等级,而这通常是维持高于一般水平的正常运行时间。当您在 Google Cloud 上运行生产工作负载时,可以使用全球分布式系统,确保在某个地区出现问题时,应用可以继续提供服务(即使可用范围变小)。实质上,该应用会激活其 DR 方案。

设计问题

  • 应用是否可以通过添加更多虚拟机来纵向扩容,而无需更改架构?
  • 架构中的每个组件是否都能通过分片或其他方式横向扩缩?
  • 客户端应用是否旨在避免跨客户端同步请求?
  • 应用能够在不发生全球中断的情况下处理整个云地区的故障吗?
  • 用户请求是否均匀分布在分片和地区中?
  • 应用能否检测超载状态并更改其行为以防止服务中断?

建议

  • 在客户端应用的错误重试逻辑中实现随机化指数退避算法。
  • 实现具有自动故障转移功能的多地区架构,以实现高可用性。
  • 使用负载平衡功能在分片和地区之间分布用户请求。
  • 将应用设计为在过载时平缓降级,提供部分响应或提供有限功能,避免完全停止工作。
  • 建立周期性数据驱动型容量规划流程,使用负载测试和流量预测来推动资源预配。
  • 制定灾难恢复程序并定期进行测试。

构建灵活的自动化部署功能

确保可以回滚所有更改

如果没有明确的方法来撤消某些类型的更改,请更改服务的设计使其支持回滚,并定期测试回滚流程。对于移动应用而言可能实现费用比较高昂,我们建议开发者应用 Firebase 远程配置以简化功能回滚。

为限时促销和发布活动分散流量

对于促销活动,例如在某个精确时间(如午夜)开始,并鼓励许多用户同时连接到服务的销售活动,请设计客户端代码,在发出请求前添加随机延迟,将流量分散到几秒内。这样可以防止在规划的开始时间出现的即时流量高峰导致您的服务器崩溃。

借助 Canary 测试实现渐进式发布

从一个小范围(例如一个区域中的几个虚拟机)开始逐步发布新版本可执行文件和配置更改。您的目标是在只有一小部分用户流量受到影响时发现 bug,然后再在全球范围内发布更改。设置一个“Canary 测试”系统,该系统会注意到此类更改,并对更改后的服务器与其余服务器的指标进行 A/B 比较,以标记异常行为。Canary 系统应提醒运营人员相关问题,甚至可能会自动暂停发布。更改通过 Canary 测试后,请逐步将其传播到更大的范围,例如先传播到一个完整的区域,然后再传播到第二个区域,从而让更改后的系统有时间逐步处理更多用户流量,以发现潜在的 bug。

自动构建、测试和部署

借助 CI/CD 流水线,将自动化测试内置到您的版本中,从而消除发布版本时费力的手动操作。执行自动集成测试和部署。

自动化很有用,但不是万能的。除了最初的开发和设置费用之外,它还带来了相当大的维护费用和可靠性风险。

我们建议您首先对系统管理团队的手动操作费用进行盘点和评估。在为自定义自动化进行投资以扩展 Google Cloud 服务和合作伙伴已提供的服务之前,请先执行此流程。通常,您可以调整 Google Cloud 自己的自动化功能,例如 Compute Engine 的自动扩缩算法。

我们认为,需要手动执行、可自动化的重复性反应式工作往往缺少长期价值,而且其增长速度与其来源不相上下。如需了解详情,请参阅 SRE 图书的消除手动操作一章。

以下是使用 Google 提供的可配置自动化功能或自定义自动化功能消除手动操作,从而为客户提供帮助的一些主要领域:

我们建议您先消除费力的手动操作,然后进行自动化,接下来充分利用 Google 提供的可配置自动化功能来减少剩余的手动操作。第三步可以与前两步同时进行,即如果手动操作费用过高(例如团队花在管理生产系统方面的时间超过 50%),则评估是否需要构建或购买其他解决方案。在构建或购买解决方案时,请考虑集成、安全、隐私权与合规费用。

如果您使用的 Google Cloud 产品或服务只能部分满足您在自动化或消除手动操作方面的技术需求,请考虑通过您的 Google Cloud 客户代表提交功能请求。这可能是我们的许多客户优先考虑的功能,或者已纳入我们的发展蓝图。若是如此,了解此功能的优先级和时间表有助于您更好地评估是选择构建自己的解决方案,还是等待 Google Cloud 推出此功能。

设计问题

  • 可执行文件和配置的更改过程是否已自动化?
  • 更改自动化是否支持对每个可能的更改进行快速回滚?
  • 对于无法回滚的更改(例如架构更改),是否有一个设计审核流程能够确保当前或旧的二进制文件版本与数据架构之间的向前和向后兼容性?
  • 系统配置文件是否能够分片,以便以增量而非全局方式发布配置更改?

建议

  • 为新版本和配置设置 Canary 测试。
  • 确定对您的团队而言哪些是费力的手动操作,并定期评估费用。
  • 在开发自定义自动化功能之前,消除不必要的手动操作/工作流。
  • 通过调整默认配置或设置默认配置(如果未提供),使用 Google Cloud 服务提供的现有自动化功能。
  • 评估构建(或购买)自定义自动化功能,判断维护费用以及服务可靠性和安全性风险是否值得。我们还建议您评估维护良好的开源软件。

构建高效的提醒功能

优化提醒延迟

在监控系统通知用户问题之前调整配置的延迟,以最大限度地减少 TTD,同时最大化信号与噪声。 使用错误预算使用率来获得最佳提醒配置。

针对表现(而非原因)触发提醒

根据对用户体验的直接影响(即不符合全局或每个客户的 SLO)触发提醒。请勿针对故障的每个可能的根本原因发出提醒,尤其是当影响仅限于单个副本时。设计良好的分布式系统可以从单副本故障中顺利恢复。

构建突发事件管理协作流程

精心设计的系统最终会有无法达到 SLO 的时候,这是不可避免的。 请注意,在缺少 SLO 的情况下,无论 SLA 包含什么内容,客户仍将根据他们以往的经验来确定可接受的服务等级,并上报给您的技术支持团队或类似团队。

为了给客户提供合适的服务,我们强烈建议您制定并定期实施突发事件管理方案。该方案可以是包含 10 项左右内容的单个页面核对清单。此过程将帮助您的团队缩短平均检测时间 (MTTD) 和平均缓解时间 (MTTM)。(我们使用的是 MTTM,而非 MTTR,因为后者的含义不明确。)“R”通常用作“repair”(修复)或“recovery”(恢复),表示“完全修复”与“缓解”。MTTM 则明确表示缓解,而非完全修复。

如果系统设计良好、运营出色,则其平均故障间隔时间 (MTBF) 也会增加。如需了解详情,请参阅“系统设计和卓越运营”部分。

构建无责备的事后分析文化和突发事件审核流程也很重要。“无责备”表示您的团队需要以客观公正的方式评估和记录遇到的问题,而不是相互指责。 错误应被视为学习机会,而不是批评的原因。始终以提高系统弹性为目标,使其能够从人为错误中快速恢复,甚至更好地检测和防止人为错误。

降低 MTTD

降低 MTTD 的前提条件是实施“可观测性”和“定义监控目标”部分中给出的建议,例如区别应用问题与底层云问题。

一组完善的 SLI 会在适当的时间向您的团队发出提醒,而不会导致过多提醒。如需获取指导,请参阅优化您的 SLI 指标:CRE 经验谈

降低 MTTM

如需降低 MTTM,请制定一个能够妥善记录、运用良好的突发事件管理方案。此外,您还应获得有关更改内容的现成数据。

突发事件管理方案示例

  • 已检测到生产问题(提醒、页面)或上报给我。
  • 我应该第一时间委托吗?是的。如果您和您的团队无法解决此问题。
  • 是否侵犯隐私权或违反安全规定?如果是,则委托给隐私权/安全团队。
  • 这是紧急事件还是存在风险的 SLO?如果不确定,请将其视为紧急事件。
  • 我是否应该让更多人参与?是的,如果受影响的客户超过 X%,或者解决时间超过 Y 分钟。如果不确定,请务必让更多人参与,尤其是在工作时间。
    • 定义主要沟通渠道,例如 IRC、Hangouts Chat 或 Slack。
    • 委托以前定义的角色,例如:
      • 突发事件指挥官:负责整体协调工作。
      • 沟通主管:负责处理内部和外部沟通。
      • 运营主管:负责缓解问题。
    • 定义突发事件的结束时间。这可能需要获得支持团队代表的确认。
  • 协作完成事后分析。
  • 参加定期举行的突发事件事后分析审核会议,讨论相关事宜并采取行动。

图表

以下是需要考虑的图表的不完整列表。突发事件响应者应该能够在单个视图中对它们一目了然。

  • 服务等级指标,例如,成功的请求数除以总数。
  • 配置和/或二进制文件发布。
  • 每秒向系统发出的请求数。
  • 系统每秒返回的错误数。
  • 每秒从系统到其依赖项的请求数。
  • 每秒从系统到其依赖项的错误数。

我们还经常见到请求和响应大小、查询费用、线程池(以查找因池耗尽而导致的回归)和以图表表示的 JVM 指标(如果适用)。

根据这些图表的位置测试一些场景。您还可以运用机器学习技术来发现这些图表的正确子集(即异常值检测技术)。

最后,如前所述,另一个常见的快速缓解方法是设计可轻松回滚的系统和更改。

建议

  • 建立团队并针对突发事件管理方案进行训练。
  • 实施“可观测性”部分的建议,以降低 MTTD。
  • 构建一个“变化内容”信息中心,以便在发生突发事件时轻松查看变化。
  • 记录查询代码段或构建数据洞察信息中心。
  • 评估 Firebase 远程配置以缓解与移动应用相关的发布问题。
  • 实施“灾难恢复”建议,降低部分突发事件的 MTTM。
  • 设计并测试配置和二进制文件回滚。
  • 实施“系统设计”和“灾难恢复”(测试)部分的建议,以提高 MTBF。

资源