被严重宕机坑惨了!多家公司向这个已经存在10年却“鲜为人知”的架构迁移
单元化架构作为一种增加冗余和有效限制站点故障影响范围的方式,在大型在线服务中越来越流行。在过去一年半时间里,Slack 将大多数面向用户的关键服务从单体架构迁移到基于单元的架构上。此前,Slack 团队在一篇文章中解释了大规模迁移原因,以及团队在此过程中所做出的工程技术权衡。
Slack 团队会在每次发生明显的服务中断后进行一次事故评审。以下是 Slack 团队内部事故评审报告的一部分摘录,该摘录总结了其中的一起事故以及 Slack 团队的发现:
2021 年 6 月 30 日上午 11 点 45 分,我们的云供应商在美国东海岸的一个可用区域发生网络中断,Slack 的大部分服务都托管在那里。连接一个可用区域和其他几个包含 Slack 服务器的可用区域的网络链路发生了间歇性故障,导致 Slack 服务器之间的连接变慢,进而出现服务降级。 当日下午 12 点 33 分,我们的云供应商自动从服务中删除了网络链接,恢复了对 Slack 客户的全部服务。经过他们的一系列自动检查之后,网络链接再次进入服务状态。 当日下午 5 点 22 分,网络链路又发生了同样的间歇性故障。下午 5 点 31 分,云供应商永久地从服务中删除了网络链接,恢复了对我们全部的服务。
乍一看,Slack 的服务遭遇了物理硬件故障,导致了一些错误。直到故障硬件被移除,问题才得到解决。然而,在事故评审过程中,不禁要问:让用户经历这样的服务中断是合理的吗?
Slack 的基础设施覆盖全球,但其核心平台托管在美国东海岸地区 (us-east-1),该公司使用可用区(AZ)进行故障隔离。在云端托管服务的构建者可以通过这种方式提高服务的可用性:即使某个 AZ 发生故障,整个服务的运行也不会受到影响。这就引出了一个问题:为什么 6 月 30 日的策略没有奏效?为什么一个 AZ 的故障会导致用户体验中断?
Slack 的高级工程师 Cooper Bethea 解释了为什么分布式系统中的故障检测可能会出现问题:
事实证明,检测分布式系统中的故障是一个难题。来自用户的单个 Slack API 请求(比如说加载一个频道中的消息)可能会分散成数百个服务后端的 RPC,所有 RPC 都必须全部完成才能向用户返回正确的响应。我们的服务前端不断尝试检测和排除出现故障的后端,但在排除出现故障的服务器之前,我们必须先记录下来一些故障!
Slack 将这种类型的故障可以归类为灰色故障。在发生灰色故障时,系统可用性对于不同的组件来说是不一样的。例如,在上述案例中,受影响 AZ 内的系统看到其 AZ 内的后端完全可用,但 AZ 外的后端不可用。反过来,未受影响 AZ 内的系统看到受影响的 AZ 是不可用的。即使是同一个受影响的 AZ 内的客户端能够看到的后端可用性也是不一样的,这取决于它们的网络流量是否碰巧流经发生故障的设备。这就需要分布式系统在处理消息和提供小动物动图的同时处理好一切故障,这是一个相当复杂的任务。
为了解决这个难题,Slack 团队决定改用一种基于单元(cell)的方法,其中每个可用区包含完全独立的后端部署,且后端组件仅限于单个可用区使用。这种方法使用一个基于 Envoy/xDS 的层将流量路由到 AZ 层面的单元。这种独立部署的方法在某种程度上是 Slack 平台异构属性的自然延伸,该平台使用了许多语言栈和服务发现接口,因此在后端服务之间引入复杂的路由逻辑会是非常麻烦的事情。
独立的架构,流量远离受影响的单元(来源:Slack 工程博客)
有了这个新架构后,Slack 就可以快速将流量从出现问题的单元转移出去,因为配置更改只需几秒钟就能传播出去。流量可以渐次(以 1% 的粒度)且优雅地转移(所有正在进行的请求都在正在排出流量的单元中完成)。
Slack 的设计路径遵循了 AWS 制定的指南,该指南在 AWS 的云原生架构系列中得到了深入探讨,其中作者提供了多种工具和技术,用来利用基于容器的计算服务提高云负载的可扩展性和弹性。AWS 架构师主张在云架构中建立强大的故障隔离边界,以应对黑天鹅事件并最大限度地减少意外故障的影响。
使用了 EKS 的基于单元的架构(来源:AWS 架构博客)
最近,在线游戏平台和创作系统 Roblox 也分享了其基于单元的架构走过的历程,以及进一步提高其平台弹性的未来计划。和 Slack 一样,Roblox 也是从一次故障中意识到,是时候采用单元化架构了。
2021 年 10 月,Roblox 遭遇了一次长达 73 小时的系统范围故障,该故障最初源于一个数据中心的小问题,但迅速演变为大规模故障。事故后分析表明,团队需要加强其基础设施的稳固性,以应对流量峰值、天气条件、硬件故障、软件错误和人为失误等各种故障因素。重点在于防止单个组件问题扩散至整个系统,并确保网络或用户持续重试操作不会引发与负载相关的级联故障。
为了应对类似 2021 年 10 月的故障,Roblox 最初在多个区域的数据中心设置了基础设施的副本,采用主备方式。这意味着当主数据中心发生重大故障时,整个系统可以切换到备份基础设施上。这种方式提供了一种应急弹性,但 Roblox 的长期目标是实现从主备数据中心到双活数据中心的转型,使两个数据中心同时处理工作负载,提高可靠性和近乎即时的故障切换能力。
Roblox 还实现了单元化架构,在数据中心内建立坚固的“防爆墙”,以防止发生整个数据中心范围的故障。Roblox 的目标是将所有服务迁移至单元中,以增强弹性和高效的工作负载管理。整个单元(每个单元可能包含 1400 台服务器)可在必要时进行修复或完全重新配置。这一过程需要确保一致性,要求服务进行容器化,并实现基础设施即代码的理念。Roblox 新的部署工具会自动确保服务跨单元分布,从而使服务所有者无需考虑复制问题。
Roblox 将单元作为一种防火门,可以将故障限制在一个单元内。目标是使单元变得可互换,以便在出现问题时更快地恢复。然而,管理单元之间的通信存在一些挑战,因为需要防止“死亡查询”,即重试查询会导致级联故障。他们正在部署短期解决方案,例如将计算服务的副本部署到每个计算单元中,并在单元间平衡流量,以此来缓解这种情况。他们的长期计划包括实现用于服务发现的下一代服务网格以及将依赖请求定向到与原始调用方相同单元的方法。这将降低故障从一个单元传播到另一个单元的风险。70% 的后端流量现在由单元提供,他们的最终目标是达到 100%。近 3 万台服务器正在运行单元,但这还不到总服务器数量的 10%。
在不中断用户的情况下迁移一个非常繁忙的在线平台的复杂性是巨大的。由于没有大量的资金购买全新的服务器来运行单元化架构基础设施,Roblox 创造性地利用了一小部分备用机器,并策略性地建立了新的、单元,逐步迁移工作负载,然后重新使用已释放的机器来进行下一次迁移。这在不同的数据中心之间造成了一些理想的单元碎片,增加了单元内的弹性。Roblox 预计将于 2025 年完成迁移,他们需要强大的工具来部署均衡的服务,并且不会干扰到用户,他们还需要进行详尽的测试,确保在单元化架构中运行的新服务的兼容性。
Roblox 的努力取得了显著成果,但针对单元化架构的工作仍在进行中。他们致力于在不断扩展规模的过程中提高效率和弹性,主要成就包括建立第二个数据中心,在主备数据中心创建单元,将超过 70%的后端服务流量迁移到单元中,以及建立实现一致性的要求。
2023 年 9 月,Roblox 在数据中心启动了双活实验,增强了可靠性并最大限度地缩短了故障转移时间。这些成果让他们获得了一个实现全面双活基础设施的计划,确定了改进系统设计的模式。
Roblox 一直致力于提升效率和弹性,设想让平台成为数百万用户可靠、高性能的实用工具,并实现实时连接十亿人。他们的基础设施目前运行在近 14 万 5 千台服务器上(大部分在本地私有混合云中心)——两年内增长了三倍。目前,Roblox 正在努力改造基础设施,使平台更具弹性、更加高效,为数百万用户提供服务,为持续的增长和创新奠定基础。
Slack 采用单元化架构的举措在社区中引发了广泛的讨论。用户 esprehn 认为,单元并不是要防止可用区故障,而是要对生产基础设施进行分区,以防止出现错误的部署和配置更改。每个 AZ 被分为许多不同的单元。另一位名为 ignoramous 的用户(自称前 AWS 员工)强调,对基于单元的架构的指南是来源于 Amazon 和 AWS 在云中为提供弹性所做的努力。
用户 tedd4u 指出基于单元的架构已经存在至少 10 年了,并附上了一篇发表于 2012 年的文章链接。文中提到,面向服务的架构(SOA)带来了对大规模提供服务的迫切需求。为了满足这些需求,一种鲜为人知的架构技术应运而生——单元化架构。
在传统的服务化架构下(如下图),服务是分层的,每一层使用不同的分区算法,每一层都有不同数量的节点,上层节点随机选择下层节点。当然这个随机是比较而言的。
传统的服务化架构,为伸缩性设计,上层节点随机选择下层节点
而在单元化架构下,服务虽然分层划分,但每个单元自成一体。按照层次来讲的话,所有层使用相同的分区算法,每一层都有相同数量的节点,上层节点也会访问指定的下层节点。因为他们已经在一起。
单元化架构,为性能和隔离性而设计,上层节点访问指定下层节点
具体来说,单元化架构具有以下优点:
单元提供了一个可并行处理的单元,能够随着用户群的增长而按需调整大小。
当需要更多容量时,可以增量式地添加单元。
单元之间相互隔离,一个单元的故障不会影响到其他单元。
单元内的存储和应用能力独立于其他单元,提供了很好的隔离性。
单元提供了多种功能,如测试升级、滚动升级以及在不同版本软件间进行测试的能力。
单元可以发生故障、进行升级,并且可以独立于其他单元分布在数据中心内。
在 2012 年,就已经有包括 Facebook 在内的多家公司采用单元化结构:
Tumblr:用户被映射到单元中,每个数据中心内存在多个单元。每个单元都有一个 HBase 集群、服务集群和 Redis 缓存集群。用户被限定在一个单元内,所有单元通过 Firehose 更新来获取所有帖子。后台任务使用 Firehose 来填充表和处理请求。每个单元存储所有帖子的单个副本。
Flickr:使用联合方法,其中所有用户数据都存储在一个分片上,该分片由不同服务的集群组成。
Facebook:消息服务将称为单元的机器和服务集群作为其系统的基本构建块。每个单元由 ZooKeeper 控制器、应用程序服务器集群和元数据存储组成。
Salesforce:Salesforce 是根据 Pod 构建的。Pod 是独立的功能集,由 50 个节点、Oracle RAC 服务器和 Java 应用程序服务器组成。每个 Pod 支持数千名客户。如果 Pod 发生故障,只有该 Pod 上的用户会受到影响。
采用单元化架构的关键在于创建可扩展且强大的服务,以提高系统的平均故障间隔时间(MTBF)。这种服务可以用作由可编程编排层协调的其他服务系统的基础组件,无论是在数据中心还是云环境中都同样有效。如果团队正在寻找更高级的组织模式,那么单元化架构是一个很好的选择。
参考链接:
https://www.infoq.com/news/2024/01/slack-cell-based-architecture/
https://news.ycombinator.com/item?id=37274871
https://www.infoq.cn/article/rBofrx6EO9VkId1mmmO3
http://highscalability.com/blog/2012/5/9/cell-architectures.html
声明:本文为 InfoQ 翻译整理,未经许可禁止转载。
“印度 CEO 毁了谷歌!”大裁员引发谷歌元老集体怀旧:20 年前为梦想而战,20 年后混口饭吃
TikTok 员工加速“出海”,薪资翻倍;老外控诉中国科技巨头抄袭:反正官司打不赢,不费那个劲了;快手上市后首次整体盈利|Q资讯
想获得如网购一样便捷的算力服务体验吗?目前,国家超算互联网开放了 1500 个“体验官”名额,让你可以体验前所未有的计算速度和数据处理能力,体验并提交《体验问卷》,还可获得价值 500 元的计算资源。席位有限,点击【阅读原文】或扫码即可报名抢位!
微信扫码关注该文公众号作者