Dubbo 支持哪些负载均衡策略?
结论先行:Dubbo 内置五种——随机(Random)、轮询(RoundRobin)、最小活跃数(LeastActive)、最短响应(ShortestResponse)、一致性哈希(ConsistentHash),另有 P2C(Power of Two Choices)。默认随机加权,权重来自提供者配置或运行时动态调整。
一、五种策略速查
| 策略 | 名字 | 核心逻辑 | 适用场景 | 风险 |
|---|---|---|---|---|
| 加权随机 | random | 按权重区间取随机数 | 通用默认 | 短时间可能重复打同一台 |
| 加权轮询 | roundrobin | 平滑加权轮询,按序分配 | 实例性能接近、需要均摊 | 慢实例会积压请求 |
| 最小活跃 | leastactive | 选活跃调用数最小的,相同则随机 | 处理耗时差异大 | 需维护计数器,有统计滞后 |
| 最短响应 | shortestresponse | 按成功调用平均耗时加权 | 长尾明显的场景 | 样本少时抖动大 |
| 一致性哈希 | consistenthash | 参数哈希 → 环 → 顺时针找节点 | 需要同一参数落到同一台(缓存) | 节点变更需虚拟节点摊平 |
| P2C | p2c | 随机取两个,选活跃数小的 | 大规模集群 | 需要足够实例数 |
二、平滑加权轮询为什么“平滑”
朴素轮询会把权重 5 的节点前五个请求全给它,造成瞬时尖峰。Dubbo 的平滑版本给每个节点维护 currentWeight,每轮加上静态权重、选中最大者、再把该节点减去总权重:
权重 A=5, B=1, C=1(总权重 7)
轮次 currentWeight 选中
1 A5 B1 C1 A → A:-2
2 A3 B2 C2 A → A:-4
3 A1 B3 C3 B → B:-4
4 A6 B-3 C4 A → A:-1
5 A4 B-2 C5 C → C:-2
6 A9 B-1 C-1 A → A:2
7 A7 B0 C0 A
七轮里 A 出现 5 次、B 与 C 各 1 次,且分布均匀,不会出现连续五次打 A。
三、配置方式
全局:
dubbo:
consumer:
loadbalance: roundrobin
方法级与权重:
@DubboReference(loadbalance = "leastactive")
private ReportService reportService;
// 提供者启动时声明权重,越大分到的流量越多
@DubboService(weight = 200)
public class ReportServiceImpl implements ReportService { }
一致性哈希还可以指定参与哈希的参数下标,避免把 userId 之外的参数也算进去:
// parameters 是键值成对出现的字符串数组
@DubboReference(
loadbalance = "consistenthash",
parameters = {"hash.arguments", "0", "hash.nodes", "160"})
private CacheService cacheService;
四、动态权重与预热
新实例刚启动时 JIT 未预热、缓存未填充,直接按权重接流会被打慢。Dubbo 提供预热机制:实例启动后权重从 1 逐步涨到配置值(默认预热 10 分钟),由 warmup 参数控制。
常见追问
- 追问:最小活跃数为什么需要“相同则随机”?活跃数相同说明负载接近,随机可以避免所有请求挤向同一个下标。
- 追问:一致性哈希的虚拟节点有什么用?真实节点少时哈希环分布不均,每个真实节点映射 160 个虚拟节点可以把倾斜控制在可接受范围。
- 追问:生产上怎么选?多数服务用默认 random;有本地缓存需求的用 consistenthash;耗时差异大的用 leastactive;发现长尾明显再考虑 shortestresponse。
小结
- 五种内置策略 + P2C,默认加权随机。
- 平滑加权轮询通过
currentWeight抵消瞬时尖峰。 - 权重可静态配置,也可运行时按活跃数动态调整,并有预热保护。
- 选型依据是“实例是否同质”和“是否存在长尾”,不是性能高低。