目录
1. swrr负载均衡算法的二宗罪
swrr是一种基于加权轮询的负载均衡算法。它根据服务器的权重来分配请求。具体而言,swrr维护一个服务器列表,每个服务器都有一个权重值,表示其处理请求的能力。当一个请求到达时,swrr会按照服务器的权重顺序依次将请求转发到服务器上,然后更新服务器的权重。这样可以实现将请求均匀地分配给具有不同处理能力的服务器。关于swrr的实现原理可以参考我的博文《深入理解nginx负载均衡round-robin算法》。
nginx的官方原生的round-robin功能就是基于swrr算法来实现的。就如其名字swrr表明的,Smooth Weighted round-robin,它比最简单的round-robin功能有了重要的改进,它不是简单的依次轮询,而是按照服务器权重平滑分配的能力,一定程度上避免了rs服务器的突发峰值的问题。
本文要细数一下swrr的两宗罪:
1.1 第一宗罪: 共振引起系统崩溃
我们先来看看阿里的真实案例。《阿里七层流量入口负载均衡算法演变之路》中提到的一个压测案例,当一个机房内的接入层tengine统一将某个rs服务器的权重从1改成2以后,被调高权重rs服务器的流量瞬间冲高了50倍左右,并且持续了7s左右的时间后QPS开始下降,流量才逐渐恢复到预期的值。
该文中给出了相关现象的详细描述,但是具体什么原因却没有详细说明。这里就来分析一下。对于swrr,如果按照nginx单个进程来说,其实它已经做得足够好了,顾名思义,它已经是平滑的了。但是,如果我们放在一个拥有32核心,甚至64核心或者更多的服务器上,那么我们开启的nginx worker进程就是32,或者64个,如果再像阿里的压测环境,可能又有几十台作为负载均衡功能的nginx前端接入服务器,那么可能就是并发运行的nginx进程就有几百个甚至上千个。swrr在每个进程中都会被初始化为一个状态,如果有三个rs server分别为A、B、C,并假设通过swrr算法,但个进程依次分配rs得到以下序列 B、C、A、B、A、C…
另外,假设总共有100个nginx worker进程在运行,我们可以想象到,第一个请求进来的时候,因为所有的nginx进程分配的第一个rs必然是B,因此第一个请求分配到的rs是B的概率是100%,那么第二个请求进来的时候,因为有99个进程将分配B,而之前分配了B的服务器将分配C,那么分配到B的概率将是99%,依次类推,第三个请求分配到B的概率也97%,这就导致了B服务器的压力在短时间内会飚得特别高,就像《阿里七层流量入口负载均衡算法演变之路》中给出的那个图像一样:
所以,关键的问题在于每个nginx的worker进程因为每个进程都步调一致,导致了“共振现象”,引起了部分rs服务器的流量突发性增高,和原本的预期背道而驰了。我们回顾一下中学物理上面介绍的一个经典的军队用统一步伐过桥最终引起大桥垮塌的案例就可以与这个案例引起共鸣,一言以蔽之,swrr引起的流量突发也是因为“共振”引起的流量突发。
当然,随着时间的推移,最终每个进程由于分配到的请求的随机性因素,由于swrr的平滑负载均衡能力,必然会慢慢达到预期的负载效果,但是,我们要注意的是,前提是因为流量