一些过载保护,防止雪崩的方法

时间:2021-02-16 15:02:41


       一般接口都有一个最大处理能力,比如每秒处理N万个请求。正常情况下,在前端允许的时延内,后端接口都能处理完请求。但到了类似抢购小米神机的场景下,后端的接口一般会承受超出平时请求量几十几百甚至几万倍的请求量,而且这写请求全部集中在一段时间内,称之为过载时间。这段时间内,后端接口的处理能力达到了极限,不停的拼命做都取不完缓冲区的请求,因为此时缓冲区的数据一直在不停累积,进入到缓冲区没有及时处理的请求,对外表现为系统繁忙、超时、没有响应;而没有进入到缓存区的数据就被丢弃,对外反应就是失败。所以可以看到,一般的抢购系统都处于长期失败或者繁忙状态。

良好的接口服务应该在有限的资源内提供有限的处理能力,良好的系统设计要能够及时发现超出接口处理能力的请求,及时阻断丢弃,而良好的前端展示应该给与用户友好的提示,使用进度条,动画等描述系统繁忙的场景,减少用户反感,同时要严格限制用户重试的频率。中间处理模块到后端接口的重试处理也要有时间和频率限制。

对接口服务来说,防止雪崩的方法一般有三种:

1、频率限制

      在接口入口处,甚至系统的入口处应该设置频率限制,为接口设置单位时间内最大的处理量,同时记录单位时间内已经处理的请求量,当请求量大于最大处理量的时候,直接拒绝外部的请求,保护内部系统的心脏承受能力。

2、超时丢弃

      这里的超时是指请求从进入接收缓存区到接口从缓存区取出请求准备处理的时间超过了一定阈值(比如前端超时时间)。如果发生超时,则说明就算处理了取出的数据,前端也已经超时了,后端接口做的就是无用功,倒不如就在这里一次性丢弃。这里的缓存区指的是内核缓存区。

      标记进入缓存区时间的方法可以有2种:

     (1)、直接利用ioctl函数的SIOCGSTAMP命令。在初始化socket的时候和取数据的时候分别调用一次,第一次是设置,第二次是获取数据进入缓存区的时间。另外还可以用recvmsg/sendmsg函数通过设置socket的SO_TIMESTAMP参数来获取请求进入网卡的时间。

    (2)、在接口和缓存区之间搭建一层interface进程只负责从缓存区读取数据打上时间戳放入供接口调用的channel中,实际业务处理接口则从channel中获取请求,同时获取时间戳。由于interface进程只负责取数据,所以效率较高,打上的时间戳可以近似认为就是请求进入缓存区的时间。

3、修改socket缓存区大小

     根据接口处理能力和前端超时时间来设置socket缓存区大小,这样的话利用socket缓存区充当队列,超过队列长度的请求就直接被丢弃了,这样也可以防止系统雪崩。只是对用户不那么友好。有人给出的参考计算式:缓冲区大小=(前端超时时间-请求处理时间-前端网络延时*2*(每秒最大处理请求数/1000)*请求包大小。

   如果系统处在过载处理时间段内,对每个请求比较超时时间也会占用一定系统资源,对于高性能的服务来说这块的影响也不能小视,所以如果能对第一次因为过载和丢弃的请求之后的请求包进行一定量的丢弃处理,可以有效减少这部分的计算资源,减轻系统的负载,使得业务能够快速恢复。


    防止雪崩涉及到整个业务的方方面面,不是单一后端服务做好就可以解决的。这里再附上专家们总结的经验以备后用。

   1、每个系统,自己的最大处理能力是多少要做到清清楚楚。

   2、每个系统要做好自我保护,量力而为,而不是尽力而为。对于超出自己处理能力范围的请求,要勇于拒绝。
   3、每个系统要有能力发现哪些是有效的请求,哪些是无效的请求。上面两个案例中,过载的系统都不具备这中慧眼,逮着请求做死的处理,雪球时其实是做无用功。
   4、前端系统有保护后端系统的义务,sla中承诺多大的能力,就只给到后端多大的压力。这就要求每一个前后端接口的地方,都有明确的负载约定,一环扣一环。
   5、当过载发生时,该拒绝的请求(1、超出整个系统处理能力范围的;2、已经超时的无效请求)越早拒绝越好。就像上海机场到市区的高速上,刚出机场就有电子公示牌显示,进入市区某某路段拥堵,请绕行。
   6、对于用户的重试行为,要适当的延缓。例如登录发现后端响应失败,再重新展现登录页面前,可以适当延时几秒钟,并展现进度条等友好界面。当多次重试还失败的情况下,要安抚用户。
   7、产品特性设计和发布上,要尽量避免某个时刻导致大量用户集体触发某些请求的设计。发布的时候注意灰度。
   8、中间层server对后端发送请求,重试机制要慎用,一定要用的话要有严格频率控制。
   9、当雪球发生了,直接清空雪球队列(例如重启进程可以清空socket 缓冲区)可能是快速恢复的有效方法。
  10、过载保护很重要的一点,不是说要加强系统性能、容量,成功应答所有请求,而是保证在高压下,系统的服务能力不要陡降到0,而是顽强的对外展现最大有效处理能力。