本文共 3113 字,大约阅读时间需要 10 分钟。
喜欢这篇论文有两个理由。首先,我们对微信的后端已经有了一些见解,其次,作者分享了已经在微信生产环境中运行了五年的过载控制系统DAGOR的设计方案。这个系统的设计专门考虑到了微服务架构的特殊性。如果你希望为自己的微服务制定策略,那么你就很有必要看看这篇文章。
此时的微信后端由3000多个移动服务组成,包括即时消息、社交网络、移动支付和第三方授权。平台每天的外部请求达到了10^10到10^11个。每个这样的请求都可以触发更多内部的微服务请求,从整体来看,微信后端需要每秒处理数亿个请求。
微信微服务系统的3000多项服务运行在20,000多台机器上,随着微信的广泛普及,这些数字在不断增加…随着微信的不断发展,微服务系统一直在快速进行服务更新迭代。从2018年的3月到5月,微信微服务系统平均每天发生近千次的变更。
微信将微服务分为“入门跳板”服务(接收外部请求的前端服务)、“共享跳板”服务(中间层协调服务)和“基本服务”(不再向其他服务发出请求的服务,也就是充当请求的接收器)。
在典型的一天,峰值请求率约为日常平均值的3倍。在一年中的某些时候(例如中国农历新年期间),峰值工作负载可以上升到日常平均值的10倍。
过载控制对于大规模在线应用程序来说至关重要,这些应用程序需要在不可预测的负载激增的情况下实现24×7服务可用性。
传统的过载控制机制是为具有少量服务组件、相对狭窄的“前门”和普通依赖关系的系统而设计的。
现代在线服务在架构和依赖性方面正变得越来越复杂,远远超出了传统过载控制的设计目标。
由于一个服务可能会向它所依赖的服务发出多个请求,并且还可能向多个后端服务发出请求,因此我们必须特别注意过载控制。作者发明了一个术语,叫作后续过载,用于描述调用多个过载服务或多次调用单个过载服务的情况。
后续过载给有效的过载控制带来了挑战。当服务过载时随机执行减载可以让系统维持饱和的吞吐量。但后续过载可能会超预期大大降低系统吞吐量…
试想一个简单的场景,其中服务A两次调用服务B,如果B开始拒绝一半传入的请求,那么A的成功概率就降到了0.25。
微信的过载控制系统叫作DAGOR。它旨在为所有服务提供过载控制,因此具有服务无关性。由于集中式全局协调成本过高,因此过载控制是以单台机器的粒度运行的。不过,它使用了一种用于处理后续过载所需的轻量级机器间协作协议。最后,当发生过载不得不进行减载时,DAGOR应该尽可能维持服务的成功率,并尽量减少在失败的服务任务上花费过多的计算资源(例如CPU、I/O)。
我们需要完成两个基本的任务:过载检测,并在检测到过载之后决定如何处理它。
对于过载检测,DAGOR使用了待处理队列中的请求的平均等待时间(即排队时间)。排队时间可以抵消调用图中较低的延迟所带来的影响(与请求处理时间相比)。即使本地服务器本身没有过载,请求处理时间也会增加。DAGOR使用基于窗口的监控,每个窗口是一秒钟,或者2000个请求,以先达到者为准。
对于过载检测,假设WeChat中每个服务任务的默认超时为500毫秒,那么用于表示服务器过载的平均请求排队时间的阈值被设置为20毫秒。这种配置已经在微信业务系统中应用了五年多,微信业务活动的稳健性已经证实了这种配置的有效性。
一旦检测到过载,我们就必须决定如何处理它,或者直接丢弃某些请求。我们发现,并非所有的请求都是平等的:
微信的操作日志显示,当微信支付和即时消息遇到服务不可用时,用户针对微信支付服务的投诉是针对即时消息服务的100倍。
为了以服务无关的方式处理这个问题,每个请求在首次进入系统时都会被赋予业务优先级。这个优先级会随所有下游请求一起流动。用户请求的业务优先级由请求的操作类型来决定。虽然有数百个入口点,但只有几十个具有显式优先级,其他入口点具有默认(较低)优先级。优先级保留在复制的哈希表中。
当过载控制被设置为业务优先级n时,将删除所有级别为n + 1的请求。这对于混合工作负载来说非常有效,但是假设我们有大量的付款请求,所有这些请求都具有相同的优先级(例如p)。系统将出现过载,这个时候将过载阈值降至p-1。一旦过载消失,过载阈值再次增加到p,于是我们又处于过载状态。要在相同优先级的请求发生过载时避免这种翻转,我们需要比业务优先级更细粒度的控制级别。
微信提供了一个很好的解决方案,它增加了基于用户ID的第二层准入控制。
入口服务通过以用户ID作为参数的哈希函数来动态生成用户优先级。每个入口服务每小时更改其哈希函数。因此,来自同一用户的请求很可能在一小时内被分配了相同的用户优先级,但在几小时内被分配了不同的用户优先级。
这提供了一种公平性,同时还在相对长的时间段内为个人用户提供一致的体验。它还有助于解决后续过载问题,因为具有高优先级的用户请求更有可能在整个调用图中得到处理。
通过组合业务优先级和用户优先级,可以为每个业务优先级提供128个用户优先级准入级别。
由于每个业务优先级的准入级别具有128个用户优先级,因此复合准入级别数量可以达到数万。复合准入级别的调整是按照用户优先级的颗粒进行的。
这里有个有趣的问题,为什么使用会话ID代替用户ID就不起作用:在遇到糟糕的服务时,这样会导致用户登录登出,那么在过载问题之上又会多出来一个用户登录问题!
DAGOR为每个服务器维护一个请求的直方图,用于跟踪超过准入优先级的请求的大致分布情况。当在窗口期间检测到过载时,DAGOR移动到第一个桶,将使预期负载减少5%。如果没有发生过载,它会移动到第一个桶,将使预期负载增加1%。
服务器将准入优先级嵌入到发送给上游服务器的每个响应消息中。通过这种方式,上游服务器获知下游服务的当前准入控制设置,可以在发送请求之前对请求执行本地准入控制。
DAGOR过载控制系统的端到端视图如下所示:
DAGOR在微信的生产环境已经运作五年了,这是对它的设计可行性的最好证明。但我们并没有为学术论文提供必要的图表,所以我们进行了一组模拟实验。下面的图表突出显示了基于排队时间而非响应时间的过载控制的好处。在发生后续过载的情况下,这些好处最为明显(图(b))。
与CoDel和SEDA相比,在进行一次后续调用时,DAGOR的请求成功率提高了50%,随后出现过载。后续请求数量越多,好处就越大:
最后,在公平性方面,CoDel在压力下更倾向于使用较小的扇出服务,而DAGOR在各种请求中表现出大致相同的成功率。
即使你不使用DAGOR,作者还是为你总结了三个宝贵的经验教训:
论文地址:
关于微信的微服务架构,微信后台基础架构负责人许家滔曾在2016年ArchSummit北京站做过分享,想要进一步了解可以查看我们整理的。
英文原文:
转载地址:http://emsdx.baihongyu.com/