负载均衡算法#
一句话答案#
常用算法:轮询、加权轮询、随机、一致性哈希(同客户端固定节点)、最少连接。
核心要点
| 算法 | 特点 |
|---|---|
| 轮询 | 简单均匀 |
| 加权轮询 | 按权重分配 |
| 随机 | 简单,大量请求趋于均匀 |
| 一致性哈希 | 同一客户端固定到同一节点 |
| 最少连接 | 分配给最闲的节点 |
平滑加权轮询(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=7,cw 表示 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 可配合健康检查模块自动降权故障节点
易错点:
- ❌ 轮询就够了——节点性能不同需要加权
- ❌ 随机不均匀——大量请求下趋于均匀