面试知识库
进阶

负载均衡算法#

一句话答案#

常用算法:轮询、加权轮询、随机、一致性哈希(同客户端固定节点)、最少连接。

核心要点
算法特点
轮询简单均匀
加权轮询按权重分配
随机简单,大量请求趋于均匀
一致性哈希同一客户端固定到同一节点
最少连接分配给最闲的节点

平滑加权轮询(Nginx smooth WRR)#

朴素加权轮询的问题: 权重 {a:5, b:1, c:1} 若用「按权重展开成序列」的简单实现,会得到 a a a a a b c——前 5 个请求全扎堆打到 a,造成瞬时不均、流量不平滑。

Nginx 的平滑加权算法(每次选节点三步):

1. 每个节点:current_weight += weight        // 各自的当前权重累加自身配置权重
2. 选出 current_weight 最大的节点作为本次结果
3. 选中者:current_weight -= total_weight    // 减去所有节点权重之和
plaintext

举例 {a:4, b:2, c:1},total=7cw 表示 current_weight:

轮次累加后 cw(a,b,c)选中选中后 cw(a,b,c)
1(4, 2, 1)a(-3, 2, 1)
2(1, 4, 2)b(1, -3, 2)
3(5, -1, 3)a(-2, -1, 3)
4(2, 1, 4)c(2, 1, -3)
5(6, 3, -2)a(-1, 3, -2)
6(3, 5, -1)b(3, -2, -1)
7(7, 0, 0)a(0, 0, 0)

7 轮序列 a b a c a b a——a 选中 4 次、b 2 次、c 1 次,比例严格符合权重,且高权重节点被均匀打散而非连续扎堆。第 7 轮后 cw 全归零,回到初始状态,序列周期循环。

为何同权重不扎堆: 选中者每次扣掉 total_weight,相当于被「压到队尾」,其它节点靠累加慢慢追上来——权重相同则退化为普通轮询,权重不同则高权重者更频繁但被错峰分散。

一致性哈希虚拟节点为何解决倾斜#

真实节点直接上环的倾斜问题: 节点数少时,少数几个哈希点把哈希环切成大小悬殊的弧段,导致每个节点负责的环区间长度不均——数据/请求分布严重倾斜;且某节点宕机时,它的全部负载会一股脑压给环上的下一个节点,引发雪崩。

虚拟节点做法: 每个物理节点映射成多个虚拟节点(如 node1#1, node1#2 … node1#150)散布在环上,路由时先找到虚拟节点、再映射回物理节点。

  • 削平倾斜: 虚拟节点越多,各物理节点的虚拟节点在环上越接近均匀分布,每个物理节点负责的总弧长趋于 1/N,方差大幅下降。
  • 故障/扩容时负载分摊: 某物理节点下线,它的 150 个虚拟节点分散在环各处,原本由它承接的请求会被分摊到环上多个不同的后继节点,而非全压给单一节点,避免单点过载。
面试回答(2分钟版)

负载均衡算法主要有五种。轮询是最简单的,按顺序依次分配请求,适合节点性能相近的场景。加权轮询在轮询基础上给高性能节点更大权重,能者多劳。随机算法简单实现,在请求量足够大时趋于均匀分布。一致性哈希把节点和请求都映射到哈希环上,同一客户端的请求总是路由到同一节点,适合需要会话亲和或本地缓存命中率的场景,比如缓存集群分片。最少连接算法把请求分配给当前连接数最少的节点,适合长连接场景比如 WebSocket。没有万能的算法,选型要看业务场景:节点性能一致用轮询或随机,性能不同用加权轮询,有状态场景用一致性哈希,长连接场景用最少连接。生产中 Nginx 支持以上所有策略,Dubbo 默认随机,Spring Cloud LoadBalancer 默认轮询。

追问与易错

追问方向:

  • “一致性哈希适合什么场景?”→ 需要会话亲和(同一客户端固定到同一节点)或缓存命中率高的场景,如缓存集群分片、CDN 节点选择
  • “最少连接数怎么实现?”→ 负载均衡器维护每个后端节点的活跃连接数,新请求分配给连接数最少的节点,适合长连接场景(WebSocket/gRPC)
  • “加权轮询怎么动态调整?”→ 根据节点健康检查结果和实时负载(CPU/内存/响应时间)动态调整权重,Nginx 的 upstream 可配合健康检查模块自动降权故障节点

易错点:

  • ❌ 轮询就够了——节点性能不同需要加权
  • ❌ 随机不均匀——大量请求下趋于均匀