一:什么是服务过载?
服务过载就是服务的请求量超过服务所能承受的大值,从而导致服务器负载过高,响应延迟加大,用户侧表现就是无法加载或者加载缓慢,这会引起用户进一步的重试,服务一直在处理过去的无效请求,导致有效请求跌 0,甚至导致整个系统产生雪崩。
二:为什么会发生服务过载?
互联网天生就会有突发流量,秒杀,抢购,突发大事件,节日,甚至恶意攻击等,都会造成服务承受平时数倍的压力,微博经常出现某明星官宣结婚或者离婚导致服务器崩溃的场景,这就是服务过载。
三:过载保护的好处
主要是为了提升用户体验,保障服务质量,在发生突发流量时仍然能够提供一部分服务能力,而不是整个系统瘫痪,系统瘫痪就意味着用户流失,口碑变差,夫妻吵架,甚至威胁生命安全
四:如何判断过载
通常判断过载可以使用吞吐量,延迟,CPU 使用率,丢包率,待处理请求数,请求处理事件等等。微信使用在请求在队列中的平均等待时间作为判断标准,就是从请求到达,到开始处理的时间。
为啥不使用响应时间?因为响应时间是跟服务相关的,很多微服务是链式调用,响应时间是不可控的,也是无法标准化的,很难作为一个统一的判断依据。
那为什么不使用 CPU 负载作为判断标准呢, 因为 CPU 负载高不代表服务过载,因为一个服务请求处理及时,CPU 处于高位反而是比较良好的表现。实际上 CPU 负载高,监控服务是会告警出来,但是并不会直接进入过载处理流程。
五、过载保护策略
1:业务优先级
对于不同的业务场景优先级是不同的, 比如登录场景是重要的业务,不能登录一切都白瞎,另外支付消息比普通消息优先级高,因为用户对金钱是更敏感的,但普通消息又比朋友圈消息优先级高,所以在微信内是天然存在业务优先级的。
用户的每个请求都会分配一个优先级,并且在微服务的链式调用下,下游请求的优先级也是继承的,比如我请求登录,那么检查密码等一系列的的后续请求都是继承登录优先级的,这就保证了优先级的一致性。
2. 用户优先级
很明显,只基于业务优先级的控制是不够的,首先不可能因为负载高,丢弃或允许通过一整个业务的请求,因为每个业务的请求量很大,那一定会造成负载的大幅波动,另外如果在业务中随机丢弃请求,在过载情况下还是会导致整体成功率很低。
为了解决这个问题,可以引入用户优先级,首先用户优先级也不应该相同,对于普通人来说通过 hash 用户 ID,计算用户优先级,为了防止出现总是打豆豆的现象,hash 函数每小时更换,跟业务优先级一样,单个用户的访问链条上的优先级总是一致的。
这里有个疑问,为啥不采用会话 ID 计算优先级呢,从理论上来说采用会话 ID 和用户 ID 效果是一样的,但是采用会话 ID 在用户重新登录时刷新,这个时候可能用户的优先级可能变了,在过载的情况下,他可能因为提高了优先级就恢复了,这样用户会养成坏习惯,在服务有问题时就会重新登录,这样无疑进一步加剧了服务的过载情况。
因为引入了用户优先级,那就和业务优先级组成了一个二维控制平面,根据负载情况,决定这台服务器的准入优先级
B,U,当过来的请求业务优先级大于 B,或者业务优先级等于 B,但用户优先级高于 U 时,则通过,否则决绝。
3.自适应优先级调整
在大规模微服务场景下,服务器的负载是变化非常频繁的,所以服务器的准入优先级是需要动态变化的,微信分了几十个业务优先级,每个业务优先级下有 128 个用户优先级,所以总的优先级是几千个。
如何根据负载情况调整优先级呢?简单的方式是从右到左遍历,每调整一次判断下负载情况,这个时间复杂度是 On, 就算使用二分法,时间复杂度也为 Ologn,在数千个优先级下,可能需要数十次调整才能确定一个合适的优先级,每次调整好再统计优先级,可能几十秒都过去了,这个方法无疑是非常低效的。