本网站内容使用人工智能(AI)或机器翻译技术翻译,可能存在错误。

Skip to content

实现大规模平台可靠性

运行任何可扩展的分布式平台都需要对可靠性做出承诺,以确保客户在需要时能够获得所需的服务。 依赖关系可能相当复杂,尤其是对于像 Roblox 这样庞大的平台。构建可靠的服务意味着,无论依赖关系的复杂程度和状态如何,任何给定的服务都不会中断(即高可用性),将无故障运行(即高质量),且不会出现错误(即容错性)。

为何可靠性至关重要

我们的账户身份团队致力于实现更高的可靠性,因为我们构建的合规服务是平台的核心组件。合规性的缺失可能带来严重后果。阻碍 Roblox 正常运行的代价非常高昂,不仅需要额外资源来恢复故障,还会导致用户体验受损。

传统可靠性方法主要侧重于可用性,但在某些情况下,这些术语会被混淆或误用。大多数可用性指标仅评估服务是否正常运行,而分区容错和一致性等关键方面却常被忽视或误解。 

根据CAP定理,任何分布式系统都只能保证这三个方面中的两个,因此我们的合规服务牺牲了一部分一致性,以换取高可用性和分区容错性。尽管如此,我们的服务仅做出了微小牺牲,并通过下文所述的合理架构调整,找到了实现良好一致性的机制。

提升可靠性的过程是迭代的,通过紧密的指标监控配合持续的工作,以在事件发生前预防、发现、检测并修复缺陷。我们的团队发现以下实践具有显著价值:

  • 正确的度量——围绕质量如何交付给客户,以及依赖项如何为我们提供质量,构建全面的可观测性。
  • 主动预判——开展架构审查和依赖项风险评估等活动。
  • 优先修正——对与我们服务相关的服务及依赖项的事件报告解决给予更高关注。

构建更高的可靠性需要一种质量文化。我们的团队早已致力于绩效驱动的开发,并深知流程的成功取决于其采用程度。团队全面采纳了该流程,并将这些实践作为标准加以应用。下图突出了该流程的组成部分:

正确测量的力量

在深入探讨各项指标之前,先对服务水平(SLO)的测量做个简要说明。

  • SLO(服务级别目标)是我们团队力求达到的可靠性目标(例如 99.999%)。
  • SLI(服务水平指标)是指在特定时间段内实际达到的可靠性(例如,去年二月的 99.975%)。
  • SLA(服务级别协议)是指在特定时间段内,我们承诺提供且用户可预期的可靠性(例如每周 99.99%)。

SLI 应反映可用性(无未处理或缺失的响应)、容错能力(无服务错误)以及达到的质量水平(无意外错误)。因此,我们将 SLI 定义为成功响应占发送到服务的总请求数的“成功率”。成功响应是指那些在正确时间和格式下发送的请求,即未发生连接、服务或意外错误的情况。

该 SLI 或成功率是从消费者(即客户端)的角度收集的。其目的是衡量实际交付给消费者的端到端体验,从而确保我们确信 SLA 已得到满足。若不这样做,将产生一种虚假的可靠性感,而忽略了与客户端连接的所有基础设施问题。与消费者 SLI 类似,我们收集依赖项 SLI 以追踪任何潜在风险。 实际上,所有依赖项 SLA 都应与服务 SLA 保持一致,且二者存在直接的依赖关系。其中一个的失败意味着所有服务的失败。我们也会追踪并报告来自服务本身(即服务器)的指标,但这并非实现高可靠性的实际来源。

除了 SLI 之外,每次构建都会收集由我们的 CI 工作流报告的质量指标。这一做法有助于严格执行质量门槛(即代码覆盖率),并报告其他有意义的指标,例如编码标准合规性和静态代码分析。这个话题此前已在另一篇文章《以性能为驱动构建微服务》中有所涉及。 在讨论可靠性时,对质量的严格把控至关重要,因为我们投入越多以追求卓越的评分,就越有信心确保系统在恶劣条件下不会发生故障。

我们的团队拥有两个仪表盘。其中一个全面展示了“消费者 SLI”和“依赖项 SLI”的各项数据,另一个则展示所有质量指标。目前我们正在努力将所有内容整合到一个仪表盘中,以便将我们关注的所有方面集中呈现,并能随时按指定时间范围生成报告。

预判故障

进行架构审查是确保可靠性的基础环节。首先,我们会确认系统是否具备冗余机制,以及当依赖项发生故障时,服务是否具备自愈能力。 除了常规的复制方案外,我们的大多数服务还采用了改进的双缓存预加载技术、双重恢复策略(如本地队列故障转移)或数据丢失应对策略(如事务支持)。这些主题内容十分丰富,值得另写一篇博客文章,但最终的最佳建议是:实施那些既考虑灾难场景又能最大限度减少性能开销的方案。

另一个需要预先考虑的重要方面是任何可能提升连接性的措施。这意味着要积极追求客户端的低延迟,并通过缓存控制技术、sidecar 以及针对超时、断路器和重试的高性能策略,让客户端做好应对极高流量的准备。 这些实践适用于任何客户端,包括缓存、存储、队列以及 HTTP 和 gRPC 中的相互依赖客户端。这也意味着要改进服务发出的健康信号,并认识到健康检查在所有容器编排中都起着重要作用。我们的大多数服务都会在健康检查反馈中提供更详细的性能退化信号,并在发送健康信号前验证所有关键组件是否正常运行。

将服务拆分为关键和非关键部分已被证明有助于聚焦于最重要的功能。我们过去曾将仅供管理员使用的端点放在同一个服务中,虽然这些端点使用频率不高,但会影响整体延迟指标。将它们移至独立的服务后,各项指标均得到了积极改善。

依赖关系风险评估是识别潜在依赖问题的关键工具。这意味着我们会识别 SLI 较低的依赖项,并要求其 SLA 与我们保持一致。在集成阶段,这些依赖项需要特别关注,因此我们会投入额外时间进行基准测试,以验证新依赖项是否足够成熟以满足我们的计划。一个很好的例子就是我们早期采用的 Roblox 存储即服务(Storage-as-a-Service)。 与该服务的集成需要提交缺陷工单并举行定期同步会议,以沟通发现的问题和反馈。所有这些工作都使用“可靠性”标签,以便我们能快速识别其来源和优先级。在确信新依赖项已准备就绪之前,我们频繁地进行特性分析。这些额外的工作有助于将依赖项提升到我们期望的可靠性水平,从而共同实现目标。

为混乱注入秩序

发生故障绝非我们所愿。但当故障发生时,其中蕴含着值得收集和学习的有价值信息,以提升可靠性。我们的团队除常规的全公司范围报告外,还制定了团队故障报告,因此无论影响规模大小,我们都会关注所有故障。 我们会明确指出根本原因,并优先处理所有工作以避免未来再次发生。作为报告的一部分,我们会协调其他团队优先修复依赖项事件,跟进确认妥善解决,并进行回顾以寻找可能适用于我们的规律。

团队针对每项服务编制《月度可靠性报告》,其中包含本文所述的所有 SLI 指标、因可靠性问题而创建的工单,以及与该服务相关的所有潜在事件。我们已习惯生成这些报告,因此下一步自然是要实现数据的自动化提取。开展这项定期工作至关重要,它提醒我们:可靠性始终是开发过程中被持续追踪和考量的关键要素。

我们的监控系统包含自定义指标和改进的警报机制,以便在已知或预期的故障发生时能第一时间收到通知。所有警报(包括误报)都会每周进行审查。此时,完善所有文档至关重要,这样用户就能清楚了解警报触发和错误发生时的具体情况,从而确保每个人都知道该如何应对(例如,操作手册和集成指南需保持一致并经常更新)。

归根结底,将质量理念融入企业文化,是实现更高可靠性的最关键且决定性因素。我们可以看到,这些应用于日常工作的实践已经初见成效。 我们的团队对可靠性有着近乎痴迷的追求,这也是我们最重要的成就。我们已增强了对潜在缺陷可能造成的影响及其可能出现时机的认知。实施了这些实践的服务始终如一地达到了其服务水平目标(SLO)和服务水平协议(SLA)。帮助我们追踪所有工作的可靠性报告,既是对团队工作的有力证明,也为其他团队提供了宝贵的经验教训。这就是可靠性文化如何渗透到我们平台各个环节的体现。

通往更高可靠性的道路并非坦途,但若想构建一个重塑人际互动方式、值得信赖的平台,这便是必不可少的。

Alberto 是 Roblox 账户身份团队的主管级软件工程师。他在游戏行业深耕多年,参与过众多 AAA 级游戏大作及社交媒体平台的开发,尤其专注于高度可扩展的架构设计。如今,他正通过应用最佳开发实践,助力 Roblox 实现业务增长与平台成熟。