平滑加权轮询通过维护current_weight与total_weight实现负载均衡:每次遍历所有节点,current_weight += weight,选最大者后减去total_weight;带权随机应避免rand()%n偏差,推荐前缀和+二分查找;一致性哈希加权宜用加权跳跃哈希而非简单虚拟节点扩容;三种策略中一致性哈希最易因环同步失败导致线上事故。

轮询策略里怎么加权重?别直接累加计数器
权重轮询不是简单地“每个节点重复调用 weight 次”,那样会破坏请求流的平滑性,尤其在节点权重差异大、总请求数少时,容易出现某节点连续被选中几十次,而另一个几乎不被选中。
真正可用的做法是维护一个当前权重(current_weight)和最大权重(max_weight),每次选择后更新:当前权重 += 节点权重,选中值最大的节点,然后该节点的当前权重 -= 总权重和。这叫“平滑加权轮询”(Smooth Weighted Round Robin)。
-
current_weight初始设为各节点权重,不是 0 - 每轮遍历所有节点,找
current_weight最大的那个 - 选中后执行
current_weight -= total_weight(total_weight是所有原始权重之和) - 其他节点的
current_weight不变,只增不减(靠 += weight 实现)
示例片段(伪代码逻辑):
for (auto& node : nodes) {
node.current_weight += node.weight;
}
auto selected = max_element(nodes.begin(), nodes.end(),
[](const auto& a, const auto& b) { return a.current_weight < b.current_weight; });
selected->current_weight -= total_weight;
随机选择带权重时,为什么不能用 rand() % N 直接映射?
因为余数法(rand() % N)在 RAND_MAX 不能被 N 整除时会产生偏差——低编号节点概率略高。而带权随机要求的是按比例采样,偏差会被权重放大。
立即学习“C++免费学习笔记(深入)”;
更稳妥的方式是:生成 [0,1) 区间浮点随机数,再做前缀和 + 二分查找。虽然比数组索引慢一点,但无偏差、可扩展、兼容任意浮点权重。
- 预先计算权重前缀和数组
prefix_sum,长度为N - 调用
std::uniform_real_distribution<double>(0.0, prefix_sum.back())</double>生成目标值 - 用
std::lower_bound在prefix_sum中查找第一个 ≥ 目标值的位置 - 该位置即选中节点下标
注意:如果权重是整数且范围不大(比如都在 1–100),也可用“别名法(Alias Method)”做到 O(1) 查询,但实现复杂、初始化开销大,一般服务场景没必要。
一致性哈希加权重后,虚拟节点还够用吗?
加了权重的一致性哈希,常见做法是按权重分配不同数量的虚拟节点(比如权重 3 就放 300 个虚拟节点,权重 1 就放 100 个)。但这只是近似——真实分布仍取决于哈希函数和节点数量,权重小的节点可能因哈希碰撞少反而负载更高。
更靠谱的做法是:放弃固定虚拟节点数,改用“加权跳跃哈希”(Weighted Jump Hash)或“增强型 Karger-Stein 哈希”,它们在构造环时就内建权重因子,不需要预生成大量虚拟节点。
- 标准
ketama或libchash不支持动态权重,硬塞虚拟节点数会放大扩容/缩容抖动 - 若必须用传统一致性哈希,建议最小虚拟节点数不低于
100 × max_weight,否则权重区分度丢失严重 -
std::hash<:string></:string>等默认哈希对短 key 分布不均,务必用xxhash或murmur3替代
三种策略实际部署时,哪个最容易出线上事故?
一致性哈希最容易在节点变更时出问题——不是算法本身错,而是工程细节没兜住。比如节点 IP 变更但没触发 rehash,或哈希环未全局同步,导致部分实例认为 A 节点已下线、另一些还认为在线,请求直接 502。
- 轮询和随机策略状态全在内存里,重启即重置,影响面可控
- 一致性哈希依赖外部协调(如 etcd/ZooKeeper 存环结构),一旦 watch 失败或版本冲突,就会静默降级成纯哈希(无权重)甚至固定路由
- 权重配置若从文件加载,要注意热更新时机:轮询可立即生效;一致性哈希需重建整个环,期间必须拒绝新连接或冻结路由表
真正的难点不在选哪种算法,而在怎么让权重变更、节点上下线、配置热更这三件事,在多进程/多线程/多机环境下原子生效——这部分没标准解法,得靠你自己的协调机制兜底。










