关于微信:微信团队分享微信后台在海量并发请求下是如何做到不崩溃的

4次阅读

共计 6617 个字符,预计需要花费 17 分钟才能阅读完成。

本文援用了文章“月活 12.8 亿的微信是如何避免解体的?”和论文“Overload Control for Scaling WeChat Microservices”的内容,有大量改变、优化和订正。

1、引言

微信是一款国民级的即时通讯 IM 利用,月活用户早就超过 10 亿,而且常常过年过节会遇到聊天音讯量暴增的状况,服务是很容易呈现过载的,但事实是微信的后盾服务始终比较稳定,那么他们是怎么做到的呢?

本文以微信发表的论文《Overload Control for Scaling Wechat Microservices》为根底(论文 PDF 原文下载见文末附件),分享了微信基于大规模微服务架构的后盾过载管控和爱护策略,以及微信依据 IM 业务特点的一些独特的架构设计做法,其中很多办法很有借鉴意义,值得一读。

(本文已同步公布于:http://www.52im.net/thread-39…)

2、微信所面临的并发压力

截止论文《Overload Control for Scaling Wechat Microservices》发表前,微信后端有超过 3000 多个服务(包含即时聊天、社交关系、挪动领取和第三方受权等),占用 20000 多台机器(随着微信的宽泛遍及,这些数字仍在一直减少)。

面向前端申请的入口服务每天须要解决 10 亿到 100 亿级别的申请,而每个这样的申请还会触发更多外部的关联服务,从整体来看,微信后端须要每秒解决数亿个申请。

随着微信的一直倒退,这些服务子系统始终在疾速进行更新迭代。以 2018 年的 3 月到 5 月为例,在短短的两个月工夫里,微信的各服务子系统均匀每天产生近千次的变更,运维压力可想而之。

另外:微信每天申请量的散布很不均匀,高峰期申请量能达到平时的 3 倍。而在非凡日子里(比方过年的时候),高峰期的流量能飙升到平时的 10 倍。有时敌人圈里有什么刷屏的流动,流量必定也会突增。由此可见,微信后端系统的并发压力相当之大。

而且:微信后端的这些服务所处的环境也是一直变动的,包含硬件故障、代码 bug、零碎变更等,都会导致服务可接受的容量动态变化。

3、微信的后端服务架构

微信后端采纳的也是微服务架构。说是微服务,其实我了解就是采纳对立的 RPC 框架搭建的一个个独立的服务,服务之间相互调用,实现各种各样的性能,这也是古代服务的根本架构。毕竟谁也不心愿看到我朋友圈崩了,导致跟我聊天也不行了,这也是微信的典型益处。

微信后端的微服务架构个别分为 3 层:

如上图所示,这 3 层服务别离是:

1)“入口跳板”服务(接管内部申请的前端服务);
2)“共享跳板”服务(中间层协调服务);
3)“根底服务”(不再向其余服务发出请求的服务,也就是充当申请的接收器)。

微信后端的大多数服务属于“共享跳板”服务,“入口跳板”服务比方登录、发送聊天音讯、领取服务等。“根底服务”也就是日常最好了解的这些信息数据接口类,比方账户数据、个人信息、好友 / 联系人信息等。

依照微信后端服务的申请量(每日在十亿到百亿之间),入口协定触发对“共享跳板”服务和“根底服务”更多的申请,外围服务每秒要解决上亿次的申请,也就是不言而喻的了。

4、什么是过载爱护

1)什么是服务过载?

服务过载就是服务的申请量超过服务所能接受的最大值,从而导致服务器负载过高,响应提早加大。

用户侧体现就是无奈加载或者加载迟缓,这会引起用户进一步的重试,服务始终在解决过来的有效申请,导致无效申请跌 0,甚至导致整个零碎产生雪崩。

2)为什么会产生服务过载?

互联网天生就会有突发流量、秒杀、抢购、突发大事件、节日甚至歹意攻打等,都会造成服务接受平时数倍的压力,比方微博经常出现某明星官宣结婚或者离婚导致服务器解体的场景,这就是服务过载。

3)过载爱护的益处

过载爱护次要是为了晋升用户体验,保障服务质量,在产生突发流量时依然可能提供一部分服务能力,而不是整个零碎瘫痪。

零碎瘫痪就意味着用户散失、口碑变差、夫妻吵架,甚至威逼生命安全(如果腾讯文档解体,这个文档正好用于救灾)。

而微信团队在面对这种量级的高并发申请挑战,做法是精细化的服务过载管制。咱们持续往下学习。

5、微信面临的过载控制技术挑战

过载管制对于大规模在线应用程序来说至关重要,这些应用程序须要在不可预测的负载激增的状况下实现 24×7 服务可用性。

传统的过载管制机制是为具备大量服务组件、绝对狭隘的“前门”和一般依赖关系的零碎而设计的。

而微信这种古代即时通讯 im 利用的全时在线服务个性,在架构和依赖性方面正变得越来越简单,远远超出了传统过载管制的设计指标。

这些技术痛点包含:

1)因为发送到微信后端的服务申请没有繁多的入口点,因而传统的全局入口点(网关)集中负载监控办法并不实用;
2)特定申请的服务调用图可能依赖于特定于申请的数据和服务参数,即便对于雷同类型的申请也是如此(因而,当特定服务呈现过载时,很难确定应该限度哪些类型的申请以缓解这种状况);
3)过多的申请停止节约了计算资源,并因为高提早而影响了用户体验;
4)因为服务的调用链极其简单,而且在一直演变,导致无效的跨服务协调的保护老本和零碎开销过高。

因为一个服务可能会向它所依赖的服务收回多个申请,并且还可能向多个后端服务发出请求,因而咱们必须特地留神过载管制。咱们应用一个专门的术语,叫作“后续过载”,用于形容调用多个过载服务或屡次调用单个过载服务的状况。

“后续过载”给无效的过载管制带来了挑战。当服务过载时随机执行减载能够让零碎维持饱和的吞吐量,但后续过载可能会超预期大大降低零碎吞吐量 …

即:在大规模微服务场景下,过载会变得比较复杂,如果是单体服务,一个事件只用一个申请,但微服务下,一个事件可能要申请很多的服务,任何一个服务过载失败,就会造成其余的申请都是有效的。如下图所示。

比方:在一个转账服务下,须要查问别离两者的卡号,再查问 A 时胜利了,但查问 B 失败,对于查卡号这个事件就算失败了。比方查问成功率只有 50%,那对于查问两者卡号这个成功率只有 50% * 50% = 25% 了,一个事件调用的服务次数越多,那成功率就会越低。

6、微信的过载管制机制

微信的微服务过载管制机制叫“DAGOR”(因为微信把它的服务间关系模型叫“directed acyclic graph”,简称 DAG)。

显然这种微服务底层的机制必须是和具体的业务实现无关的。DAGOR 还必须是去中心化的,否则的话在微信这么大且散布不均的流量下,过载管制很难做到实时和精确。同时也无奈适应微服务疾速的性能迭代公布(均匀每天要产生近 1000 次的微服务高低线)。

此外,DAGOR 还须要解决一个问题:服务调用链很长,如果底层服务因为过载爱护抛弃了申请,下层服务消耗的资源全节约了,而且很影响用户体验(想想进度条走到 99% 通知你失败了)。所以过载管制机制在各服务之间必须有协同作用,有时候须要思考整个调用链的状况。

首先咱们来看怎么检测到服务过载。

7、微信如何判断过载

通常判断过载能够应用吞吐量、提早、CPU 使用率、丢包率、待处理申请数、申请处理事件等等。

微信应用在申请在队列中的均匀等待时间作为判断规范。均匀等待时间就是从申请达到,到开始解决的工夫。

为啥不应用响应工夫?因为响应工夫是跟服务相干的,很多微服务是链式调用,响应工夫是不可控的,也是无奈标准化的,很难作为一个对立的判断根据。

那为什么也不应用 CPU 负载作为判断规范呢?因为 CPU 负载高不代表服务过载,因为一个服务申请解决及时,CPU 处于高位反而是比拟良好的体现。实际上 CPU 负载高,监控服务是会告警进去,然而并不会间接进入过载解决流程。

腾讯微服务默认的超时工夫是 500ms,通过计算每秒或每 2000 个申请的均匀等待时间是否超过 20ms,判断是否过载,这个 20ms 是依据微信后盾 5 年摸索进去的门槛值。

采纳均匀等待时间还有一个益处是:独立于服务,能够利用于任何场景,而不必关联于业务,能够间接在框架上进行革新。

当均匀等待时间大于 20ms 时,以肯定的降速因子过滤调局部申请,如果判断均匀等待时间小于 20ms,则以肯定的速率晋升通过率,个别采纳快降慢升的策略,避免大的服务稳定,整个策略相当于一个负反馈电路。

8、微信的过载控制策略

微信后盾一旦检测到服务过载,就须要依照肯定的过载保户策略对申请进行过滤管制,来决定哪些申请能被过载服务解决,哪些是须要抛弃的。

后面咱们剖析过,对于链式调用的微服务场景,随机抛弃申请会导致整体服务的成功率很低。所以申请是依照优先级进行管制的,优先级低的申请会优先抛弃。

那么从哪些维度来进行优化级的分级呢?

8.1 基于业务的优先级管制
对于微信来说,不同的业务场景优先级是不同的,比方:

1)登录场景是最重要的业务(不能登录所有都白瞎);
2)领取音讯比一般 im 聊天音讯优先级高(因为用户对金钱是更敏感的);
3)一般音讯又比朋友圈音讯优先级高(必竟微信的实质还是 im 聊天)。

所以在微信内是人造存在业务优先级的。

微信的做法是,事后定义好所有业务的优先级并保留在一个 Hash Table 里:

没有定义的业务,默认是最低优先级。

业务优先级在各个业务的入口服务(Entry Services)中找到申请元信息里。因为一个申请胜利与否依赖其上游服务所有的后续申请,所以上游服务的所有后续申请也会带上雷同的业务优先级。当服务过载时,会解决优先级更高的申请,抛弃优先级低的申请。

然而,只用业务优先级决定是否抛弃申请,容易造成零碎平稳,比方:

1)领取申请忽然上涨导致过载,音讯申请被抛弃;
2)抛弃音讯申请后,零碎负载升高了,又开始解决音讯申请;
3)然而,解决音讯申请又导致服务过载,又会在下一个窗口摈弃音讯申请。

这样重复调整服务申请管制,整体体验十分不好。所以微信须要更精细化的服务申请管制。

PS:微信尝试过提供 API 让服务提供方本人批改业务优先级,起初在实践中发现这种做法在不同的团队中极难治理,且对于过载管制容易出错,最终放弃了。

8.2 基于用户的优先级管制
很显著,正如上节内容所述,只基于业务优先级的管制是不够的:

1)首先不可能因为负载高,抛弃或容许通过一整个业务的申请,因为每个业务的申请量很大,那肯定会造成负载的大幅稳定;
2)另外如果在业务中随机抛弃申请,在过载状况下还是会导致整体成功率很低。
为了解决这个问题,微信引入用户优先级。

微信在每个业务优先级内按用户 ID 计算出的 128 个优先级:

首先用户优先级也不应该雷同,对于普通人来说通过 hash 用户惟一 ID 计算用户优先级(这个 hash 函数每小时变一次,让所有用户都有机会在绝对较长的工夫内享受到高优先级,保障“偏心”)。跟业务优先级一样,单个用户的拜访链条上的优先级总是统一的。

这里有个疑难:为啥不采纳会话 ID 计算优先级呢?

从实践上来说采纳会话 ID 和用户 ID 成果是一样的,然而采纳会话 ID 在用户从新登录时刷新,这个时候可能用户的优先级可能变了。在过载的状况下,他可能因为进步了优先级就复原了。

这样用户会养成坏习惯,在服务有问题时就会从新登录,这样无疑进一步加剧了服务的过载状况。

于是,因为引入了用户优先级,那就和业务优先级组成了一个二维管制立体。依据负载状况,决定这台服务器的准入优先级(B,U),当过去的申请业务优先级大于 B,或者业务优先级等于 B,但用户优先级高于 U 时,则通过,否则决绝。

下图就是这个“优先级(B,U)”管制逻辑(咱们会在前面再具体探讨):

8.3 自适应优先级调整
在大规模微服务场景下,服务器的负载变动是十分频繁的。所以服务器的准入优先级是须要动态变化的,微信分了几十个业务优先级,每个业务优先级下有 128 个用户优先级,所以总的优先级是几千个。

如何依据负载状况调整优先级呢?

最简略的形式是从右到左遍历:每调整一次判断下负载状况。这个工夫复杂度是 O(n), 就算应用二分法,工夫复杂度也为 O(logn),在数千个优先级下,可能须要数十次调整能力确定一个适合的优先级,每次调整好再统计优先级,可能几十秒都过来了,这个办法无疑是十分低效的。

微信提出了一种基于直方图统计的办法疾速调整准入优先级:服务器上维护者目前准入优先级下,过来一个周期的(1s 或 2000 次申请)每个优先级的申请量。当过载时,通过消减下一个周期的申请量来加重负载。假如上一个周期所有优先级的通过的申请总和是 N,下一个周期的申请量要缩小 N*a,怎么去缩小呢?每晋升一个优先级就缩小肯定的申请量,始终晋升到 缩小的数目大于指标量,复原负载应用相同的办法,只不是系数为 b,比 a 小,也是为了快降慢升。依据经验值 a 为 5%,b 为 1%。

为了进一步加重过载机器的压力,能不能在上游过载的状况下不把申请发到上游呢?否则上游还是要承受申请、解包、抛弃申请,白白的节约带宽,也减轻了上游的负载。

为了实现这个能力:在每次申请上游服务时,上游把以后服务的准入优先级返回给上游,上游保护上游服务的准入优先级,如果发现申请优先级达不到上游服务的准入门槛,间接抛弃,而不再申请上游,进一步加重上游的压力。

9、试验数据

微信的这套服务过载控制策略(即 DAGOR)在微信的生产环境曾经运作多年,这是对它的设计可行性的最好证实。

但并没有为学术论文提供必要的图表,所以微信同时进行了一组模拟实验。

上面的图表突出显示了基于排队工夫而非响应工夫的过载管制的益处。在产生后续过载的状况下,这些益处最为显著(图右)。

10、小结一下

微信的整个过载管制逻辑流程如下图所示:

针对下面这张图,咱们来解读一下:

1)当用户从微信发动申请,申请被路由到接入层服务,调配对立的业务和用户优先级,所有到上游的字申请都继承雷同的优先级;
2)依据业务逻辑调用 1 个或多个上游服务,当服务收到申请,首先依据本身服务准入优先级判断申请是承受还是抛弃(服务自身依据负载状况周期性的调整准入优先级);
3)当服务须要再向上游发动申请时,判断本地记录的上游服务准入优先级(如果小于则抛弃,如果没有记录或优先级大于记录则向上游发动申请);
4)上游服务返回上游服务须要的信息,并且在信息中携带本身准入优先级;
5)上游承受到返回后解析信息,并更新本地记录的上游服务准入优先级。

微信的整个过载控制策略有以下三个特点:

1)业务无关的:应用申请等待时间而不是响应工夫,制订用户和业务优先级,这些都与业务自身无关;
2)高效且偏心:申请链条的优先级是统一的,并且会定时扭转 hash 函数调整用户优先级,过载状况下,不会总是影响固定的用户;
3)独立管制和联结管制联合:准入优先级取决于独立的服务,但又能够联结上游服务的状况,优化服务过载时的体现。

11、写在最初

微信团队的分享只提到过载管制,但我置信服务调用方应该还有一些其余机制,可能解决不是因为上游服务过载,而是因为网络抖动导致的申请超时问题。

微信的这套微服务过载管制机制(即 DAGOR)提供的服务无关、去中心化、高效和偏心等个性很好地在微信后端跑了很多年。

最初,微信团队还分享了他们设计和运维 DAGOR 贵重教训:

1)大规模微服务架构中的过载管制必须在每个服务中实现扩散和自治;
2)过载管制应该要思考到各种反馈机制(例如 DAGOR 的合作准入管制),而不是仅仅依赖于开环启发式;
3)应该通过剖析理论工作负载来理解过载管制设计。

12、参考资料

[1] Overload Control for Scaling WeChat Microservices
[2] 罗神解读“Overload Control for Scaling WeChat Microservices”
[3] 2W 台服务器、每秒数亿申请,微信如何不“失控”?
[4] DAGOR:微信微服务过载控制系统
[5] 月活 12.8 亿的微信是如何避免解体的?
[6] 微信朋友圈千亿访问量背地的技术挑战和实际总结
[7] QQ 18 年:解密 8 亿月活的 QQ 后盾服务接口隔离技术
[8] 微信后盾基于工夫序的海量数据冷热分级架构设计实际
[9] 架构之道:3 个程序员成就微信朋友圈日均 10 亿发布量[有视频]》
[10] 疾速裂变:见证微信弱小后盾架构从 0 到 1 的演进历程(一)
[11] 一份微信后盾技术架构的总结性笔记》

13、论文原文

论文 PDF 请下载此附件:
(因无奈上传附件,请从此链接:http://www.52im.net/thread-39… 文末的“参考资料”附件中下载)

论文 PDF 全部内容概览:

(本文已同步公布于:http://www.52im.net/thread-39…)

正文完
 0