前言
一般情况下我们将负载均衡为分客户端负载均衡与服务端负载均衡(代理)。服务端负载均衡通常是使用现成的软件产品(如nginx)实现,其功能也更全面,比如它与K8s可以很好的结合使用,一定程序上降低了开发和维护的成本。但对于 RPC 服务而言,服务端负载均衡会增加两次额外的网络跳数(往返),并且它还会带来一些其他成本和潜在的问题,所以我们目前主要采用的是客户端负载均衡。本文则主要介绍比较常见的客户端负载均衡方法
典型场景如:客户端通过服务发现模块(如 ZK)获取可用的后端结点列表,然后使用某种策略选择一个后端结点进行访问
随机
加权随机
当后端结点处理能力不尽相同时,可以为每个后端结点都设置一个权重,权重越大,被访问的概率越大。其实现比较简单,通过生成随机数,判断落在权重对应的区间内即代表选择了这个结点
轮询
简单轮询是比较常见的负载均衡方法,它适用于后端结点是无状态且处理能力相同的情况,即来了一个请求就选择_下一个_后端结点进行访问;轮询也可以结合动态增删后端结点使用
普通加权轮询
当后端结点处理能力不尽相同时,可以增设权重,权重大的结点被访问较多。普通的加权轮询方式在负载均衡之加权轮询算法中有所描述,但它在某些特定的权重下时并不能产生比较均匀的后端结点访问序列
平滑加权轮询
nginx中实现了一种平滑加权轮询算法,它的算法描述如下:
- 步骤1:初始时每个结点当前权重为0
- 步骤2:更新每个结点的权重:结点当前权重 + 结点初始权重
- 步骤3:选择当前权重最大的结点,并把它的当前权重减去所有结点的初始权重总和
- 步骤4:返回执行步骤2
nginx平滑的基于权重轮询算法分析中分别对基于权重和平滑两方面进行了证明,其结论为:
- 访问次数为所有权重之和时,每个结点被访问的次数为其初始权重值
- 客户端并不是连续其初始权重值这么多次访问某个结点
一致性哈希
背景
另一种选择后端结点的方法是哈希,通过哈希函数将数据映射成一个值,然后可用于将数据打乱以达到分布上的均匀并映射到某后端结点,比如 hash(request)%n,n为后端结点的数量。当后端结点不变的理想情况下,哈希方法可以应用于有状态的后端服务结点情景;当考虑后端结点增删的情况,原来的request得到的哈希值是不会改变的,可是取模的时候因为结点的数量发生了变化,这导致了原来是 A 后端结点处理请求,现在可能是 B 处理,这并不适用有状态的后端服务结点,即有数据迁移问题。一致性哈希就是在哈希方法的基础上解决:相同的请求尽量落到相同的后端结点上
哈希环法
一致性
一致性哈希是将数据哈希成0~2^32-1(哈希环)之间的一个值,与普通哈希方法中的取模不同,一致性哈希方法将后端结点也哈希到了这个范围内的某个值,获取数据的哈希值后会向后查找第一个遇到的后端结点。由于哈希函数会保证相同输入产生相同的输出,当后端结点删除后再次加入,那么原来属于这个后端结点处理的请求也会回来
均匀性
如果数据量很大,那么数据在哈希环上的分布可能是比较均匀的;但由于后端结点数量有限,它们很有可能在哈希环上是不均匀分布的(就算能均匀的分布,在有后端结点增删时也会变的不均匀), 一致性哈希通过设置虚拟结点让后端结点在哈希环上的分布尽可能均匀,并且在后端结点增删时将数据尽可能均匀分配到现有所有后端结点上
每个后端结点对应的虚拟结点也是采用同样的方法哈希到环上,而且工程实现中能以二分查找的方法查找数据哈希值后面遇到的第一个(虚拟)后端结点,增大虚拟结点的数量可以显著减少数据在后端结点上分布的方差;此外,理论上还可以对不同后端结点设置不同虚拟结点个数,从而支持后端结点处理能力不同的情况
最小连接数
以短连接情况为例,当请求到来时,客户端会选择当前连接数最少的一个后端结点来处理请求,从而在后端服务连接数量的角度进行负载均衡。使用这种方法时有以下两点需要考虑:
- 如何准确获取各个后端结点的连接数量:显然最准确的方法是实时统计每个后端结点与所有客户端的连接总数
- 后端结点连接数量相同:多个客户端如何选择后端结点则是再次需要负载均衡的情况,最简单的方法就是随机选择一个(或者以随机顺序保存所有后端结点然后选择第一个)
举例来说,当只在客户端维护所有可用后端结点与自身的连接数时,最小连接数负载均衡的效果有可能会更差。比如当每个客户端的请求 QPS 都较低,并且请求大部分都是串行来的(这个请求没返回前还没有下次请求到来),那么每次请求到来时它与所有可用后端结点的连接均为0,此时每个客户端如果都只选择了同一个后端结点访问,从服务端看则会发现这个后端结点 QPS 和延时比其他都高,即出现了上面提到的需要再次负载均衡的情况
预热负载均衡
当有新的后端服务结点加入时,为了避免大量请求在一瞬间到达冷启动的服务结点,通常需要做预热操作,即通过某种负载均衡的方法,逐渐的将流量放至新加入的结点,经过一段时间后新加入结点的缓存已经被预热,再将新加入结点与其他结点同等对待
预热加权
预热一致性哈希
参考
gRPC Load Balancing
RPC - 负载均衡
nginx平滑的基于权重轮询算法分析
深入一致性哈希算法原理
一致性哈希的分析与实现
分布式技术探索:一致性哈希
A Guide to Consistent Hashing
Consistent hashring sharding is very unbalanced
跳跃一致性哈希法
Maglev一致性哈希法
从一致性 hash 到 ceph crush
网络负载均衡器中的动态权重功能