写点什么

Slack 蜂窝架构迁移:背后的技术策略与挑战

作者丨Cooper Bethea

  • 2023-09-12
    北京
  • 本文字数:3321 字

    阅读完需:约 11 分钟

大小:1.83M时长:10:38
Slack蜂窝架构迁移:背后的技术策略与挑战

近年来,蜂窝架构(Cell-Based Architecture)作为一种增加冗余和有效限制站点故障影响范围的方式,在大型的在线服务中越来越流行。为了实现这些目标,在过去的一年半里,我们将 Slack 最关键的面向用户的服务从单体架构迁移到了基于蜂窝的架构。在本系列文章中,我们将解释我们为什么要进行大规模迁移、介绍蜂窝拓扑设计以及我们在此过程中所做出的工程技术权衡,并讨论我们成功对许多相连接的服务进行深度改造所采用的策略。

 

背景说明:事故



2021 年 6 月 30 日事故中的 TCP 重传图表

 

在 Slack,我们会在每一次发生明显的服务中断后进行一次事故评审。以下是我们内部事故评审报告的一些摘录,总结了其中的一起事故和我们的发现:

 

太平洋时间 20121 年 6 月 30 日上午 11 点 45 分,我们的云供应商在美国东海岸的一个可用区域发生网络中断,Slack 的大部分服务都托管在那里。连接一个可用区域和其他几个包含 Slack 服务器的可用区域的网络链路发生了间歇性故障,导致 Slack 服务器之间的连接变慢,进而出现服务降级。

 

太平洋时间 2021 年 6 月 30 日下午 12 点 33 分,我们的云供应商自动从服务中删除了网络链接,恢复了对 Slack 客户的全部服务。经过他们的一系列自动检查之后,网络链接再次进入服务状态。

 

太平洋时间 20121 年 6 月 30 日下午 5 点 22 分,网络链路又发生了同样的间歇性故障。下午 5 点 31 分,云供应商永久地从服务中删除了网络链接,恢复了对我们全部的服务。

 

乍一看,这似乎没什么大不了。我们的服务所使用的一块物理硬件发生了故障,因此出现了一些错误,直到发生故障的硬件被移除。然而,在进行事故评审时,我们不禁问自己:让我们的用户体验到这样的中断是合理的吗?

 

Slack 运营着一个全球性的、多区域的边缘网络,但我们的大多数核心计算基础设施都位于单个地区(us-east-1)的多个可用区域内。可用区域(AZ)是指单个区域内的隔离的数据中心,它们除了可以提供物理隔离之外,也会限制我们所依赖的云服务组件(虚拟化、存储、网络等)的故障影响范围,这样就不会在多个 AZ 中同时发生故障。在云端托管服务的构建者(如 Slack)可以通过这样的一种方式来构建服务——在一个区域内整个服务的可用性高于任何一个 AZ 的可用性。那么问题来了:为什么这个策略在 6 月 30 日没有奏效?为什么一个 AZ 发生故障会让用户体验到中断?

 

事实证明,在分布式系统中检测故障是一个难题。来自用户的一个针对 Slack API 的请求(例如,在一个频道中加载消息)可能会扇出数百个发给后端服务的 RPC,每个 RPC 都必须完成调用才能向用户返回正确的响应。我们的服务前端不断尝试检测和排除发生故障的后端,但在能够排除发生故障的服务器之前必须先将故障记录下来!让事情变得难上加难的是,我们的一些关键数据存储(包括我们的主数据存储 Vitess)提供了高度一致的语义,这对应用程序开发人员来说非常有用,但也要求任何写入都要有可用的后端。如果一个分片主节点对应用程序前端不可用,那么到该分片的写入将会失败,直到主分片返回错误或一个次分片被提升为主分片。

 

我们可以将上述的中断归类为灰色故障。在发生灰色故障时,系统可用性对于不同的组件来说是不一样的。在我们的事故中,受影响 AZ 内的系统看到其 AZ 内的后端完全可用,但 AZ 外的后端不可用。反过来,未受影响 AZ 内的系统看到受影响的 AZ 是不可用的。即使是同一个受影响的 AZ 内的客户端能够看到的后端可用性也是不一样的,这取决于它们的网络流量是否碰巧流经发生故障的设备。这就好比要求分布式系统在为我们的客户处理消息和提供小动物动图的同时处理好一切故障,这是一个相当复杂的任务。

 

我们对这个难题的解决方案并不是试图去自动修复灰色故障,而是通过利用人类的判断力来让计算机的工作变得更容易。工程师们很清楚,在发生宕机时,主要的问题在于一个 AZ 不可达——我们汇总的目标 AZ 的每一张图表都与上面的重传图很相似。如果我们有一个可以告诉所有系统“这个 AZ 已坏,请避开它”的按钮,我们肯定会把它盘得发亮!因此,我们开始着手构建这样的按钮,可以将流量从 AZ 中抽走。

 

我们的解决方案:AZ 就是会被引流的蜂窝单元

 

与其他许多基础设施一样,AZ 引流按钮在概念上很简单,但在实践中却很复杂。我们的设计目标是:

 

  1. 尽可能在 5 分钟内减少 AZ 内的流量。Slack 的 99.99%可用性 SLA 只允许我们每年不到 1 小时的总体不可用,因此,为了有效地保持这种可用性,我们需要能够快速奏效的工具。

  2. 引流不能导致对用户可见的错误。引流是一种通用的缓解措施:只要故障包含在单个 AZ 内,即使尚未清楚导致故障的根本原因是什么,也可以有效地使用引流来缓解故障。这是一种实验性的方法,在发生故障期间,运维人员可以尝试对 AZ 进行引流,看看故障是否能够恢复,如果不能,则进行放流。如果引流会导致额外的错误,那么这种方法就没有用了。

  3. 引流和放流必须是增量的。在放流时,运维人员将流量的 1%分配给 AZ,看看它是否已经恢复。

  4. 引流机制不能依赖于被引流的 AZ 内的资源。例如,只是通过向每台服务器发送 SSH 命令并强制其关闭健康检查机制来激活引流是不行的。这是为了确保即使 AZ 完全离线也可以进行引流。

 

一种符合这些需求的简单实现是向每个 RPC 客户端发送一个信号,当客户端接收到这个信号时,它们会让流向特定 AZ 的一定百分比的流量失败。这个方案隐含了很多复杂性。Slack 没有共享代码库,甚至没有共享运行时,处理用户请求的服务使用多种语言编写,如 Hack、Go、Java 和 C++,这就需要为每一种语言单独实现客户端。除此之外,我们还支持许多内部服务发现接口,包括 Envoy xDS API、Consul API,甚至 DNS。况且,DNS 没有为 AZ 或部分引流等机制提供抽象,客户端只希望能够解析 DNS 地址并接收 IP 列表。最后,我们在很大程度上依赖了开源系统,如 Vitess,要修改代码,就需要在内部维护分支,并做一些额外的工作,将变更合并到上游,这并不是一份令人愉悦的差事。

 

我们采用的主要策略叫作“筒仓(Siloing)”。如果服务只从其所在的 AZ 内接收流量,并且只向该 AZ 内的服务器发送流量,那么这个服务就可以被称为一个筒仓。从整体上看,这种架构的效果是:每个服务似乎都有 N 个虚拟服务,每个 AZ 中有一个。重要的是,我们可以通过对某个 AZ 内的用户请求进行重定向来有效地将 AZ 内所有筒仓服务的流量抽走。如果没有来自用户的新请求到达筒仓所在的 AZ,那么这个 AZ 的内部服务自然会停止,因为它们没有新的工作要做。



我们最初的架构,后端分布在各个 AZ 中,因此错误会出现在所有 AZ 的前端

 

最终,我们得到了一个蜂窝架构。所有服务都存在于所有 AZ 中,但每个服务只与其 AZ 内的服务通信。一个 AZ 内的系统故障被包含在该 AZ 内,我们可以动态路由流量以避开这些故障,只需在前端重定向即可。



筒仓架构,一个 AZ 中的故障被包含在该 AZ 中,流量可能被抽走

 

有了筒仓架构,我们就可以将精力集中在一个地方来实现流量转换:将来自用户的查询路由到 us-east-1 区域的核心服务。在过去的几年里,我们进行了大量投入,从 HAProxy 迁移到了 Envoy/xDS 生态系统,因此我们所有的边缘负载均衡器现在都在运行 Envoy,并从我们内部的 xDS 控制平面 Rotor 接收配置。因此,我们能够通过简单地使用两个开箱即用的 Envoy 功能来进行 AZ 引流:加权集群和基于 RTDS 的动态权重分配。在对一个 AZ 进行引流时,我们只需通过 Rotor 向边缘 Envoy 负载均衡器发送一个信号,指示它们在 us-east-1 重新分配每个 AZ 的目标集群权重。如果 us-east-1 某个 AZ 的权重变为零,Envoy 将继续处理请求,但会将所有新请求分配给另一个 AZ,也就完成了对这个 AZ 的引流。我们来看看这是如何满足我们的目标的:

 

  1. 通过控制平面的传播为秒级,Envoy 负载均衡器将立即应用新的权重。

  2. 引流不会丢失请求,负载均衡层不会放弃任何一个查询。

  3. 权重提供粒度为 1%的增量式引流。

  4. 边缘负载均衡器完全位于不同的区域,控制平面有区域副本,可以抵御任意的单 AZ 故障。

 

下图是我们逐步将流量从一个 AZ 引到另外两个 AZ 时每个 AZ 的带宽情况。注意图中的“膝盖”部分,它反映了 Envoy/xDS 实现为我们提供的快速、大粒度的传播保证。



单 AZ 的每秒查询走势

  

原文链接:


https://slack.engineering/slacks-migration-to-a-cellular-architecture/


相关阅读:


自定义跟踪架构:Slack 高效解决通知问题

Slack实时消息处理架构,更新、更快、更稳定

Slack工程师如何解决最常见的移动开发痛点

Zoom和Slack的第二曲线

2023-09-12 09:496745

评论

发布
暂无评论
发现更多内容

“阿里爸爸”最新产出:Java面试突击核心讲(1658页),转载40W+

做梦都在改BUG

Java java面试 Java八股文 Java面试题 Java面试八股文

终于拿到了阿里2023年度九大Java技术文档——面试题+文档+白皮书

三十而立

Java 面试 java面试

工赋Meetup | 价值驱动的技术交流Call你来!4月2日上海见

工赋开发者社区

某厂Java一面:一道JVM面试题引发的“栈帧”血案

Java你猿哥

Java 面试 JVM Java虚拟机

GitHub置顶神作开源!世界名著《Spring实战(第6版)》全彩文档

做梦都在改BUG

Java spring 框架

工赋开发者社区 | 做好生产线的规划与布局,能给工厂带来什么好处?

工赋开发者社区

多功能代码编辑器:CodeRunner激活版

真大的脸盆

代码编辑器 代码编辑 编辑代码

简单好用的剪切板工具:Paste激活版

真大的脸盆

Mac 软件 mac剪切板工具 剪切板工具

quarkus2.13.7搭建与基础开发环境配置总结

刘一江

GraalVM Quarkus java

阿里内部总结的微服务笔记,从入门到精通小白也能学的会

做梦都在改BUG

Java 微服务 Spirng Cloud

阿里资深架构师三年整理分享:java面试核心知识点原理篇文档

三十而立

Java 程序员 IT java面试

IDEA 热部署,修改代码不用重启项目

源字节1号

软件开发 开源治理 小程序开发

教你用华为云玩转物联网开发

程思扬

华为 物联网 华为云

Java面试题大全(2023最新版)1500+大厂面试题附答案详解

采菊东篱下

Java 编程 面试

1658 页的《Java 面试突击核心讲》在牛客网火了,完整版 PDF 开放下载!

采菊东篱下

Java 面试

ZBC新一轮流动性收益计划迎来新通缩,APR高达100%

威廉META

阿里资深架构师三年整理分享:java面试核心知识点原理篇文档

三十而立

Java 程序员 面试 IT java面试

Spring、Spring MVC、Spring Boot三者的关系还傻傻分不清楚?

三十而立

Java 程序员 面试 IT java面试

ZBC新一轮流动性收益计划迎来新通缩,APR高达100%

鳄鱼视界

ZBC新一轮流动性收益计划迎来新通缩,APR高达100%

西柚子

彩印图文版《Elasticsearch实战》文档,阿里内部共享,堪称精品

做梦都在改BUG

Java Elastic Search

牛人!百度T9大佬纯手打的Kafka学习笔记,吃透已胜过80%Java求职者

Java你猿哥

kafka 面试 面经 Kafka知识点

深入浅出ThreadLocal

做梦都在改BUG

Java 多线程 ThreadLocal

Nacos心跳机制实现快速上下线

做梦都在改BUG

Java Spring Cloud nacos

深入解析线程池,就这一篇

Java你猿哥

Java 线程池 线程池工作原理 Java工程师 线程池状态

5年Java经验字节社招:半月3次面试,成功拿到Offer

Java你猿哥

Java 面试 面经 校招 春招

一文总结Java的23种设计模式

做梦都在改BUG

Java 设计模式

点击量破百万!阿里内产微服务进阶讲义,简直是Java开发者的福音

Java你猿哥

Java 面试 面经 Java工程师

SpringBoot实现对配置文件中的明文密码加密

做梦都在改BUG

Java Spring Boot 框架

存储容量启动会圆满召开

科技热闻

PyTorch 深度学习实战 | DIEN 模拟兴趣演化的序列网络

TiAmo

深度学习 迭代跟进

Slack蜂窝架构迁移:背后的技术策略与挑战_架构_InfoQ精选文章