4. 负载均衡策略:轮询、加权轮询、最少连接、一致性哈希

各位同学,咱们今天聊聊负载均衡策略。说实话,这是路由系统里最核心的环节之一。你想想看,上游有几十上百个报价源,下游有成千上万的请求涌进来,怎么把请求分出去,直接决定了系统的吞吐和稳定性。

我这些年踩过的坑,有一半都跟负载策略选型有关。选对了,系统稳如老狗;选错了,半夜三点被报警电话叫醒。嗯,咱们一个一个来看。

4.1 轮询(Round Robin)—— 最朴素的公平

轮询,说白了就是「挨个来」。请求1给节点A,请求2给节点B,请求3给节点C,然后回到A继续。这是最简单的策略,没有之一。

我刚开始做路由系统时,第一个版本用的就是轮询。为什么?因为快,因为无状态,因为不需要知道后端任何信息。

适用场景:后端节点性能完全一致,且请求处理时间相近。

但这里有个坑。我曾经在一个项目里,所有报价源服务器配置一模一样,心想轮询总没问题吧?结果跑了一个月,发现某台机器的CPU总是比其他机器高20%。查了半天,原来是这台机器上跑了个定时任务,虽然配置一样,但实际可用资源已经不一样了。

注意:轮询假设所有节点「平等」。一旦节点出现性能偏差,轮询就会导致「慢节点拖慢全局」。

4.2 加权轮询(Weighted Round Robin)—— 给强者更多机会

加权轮询,就是在轮询的基础上,给每个节点配一个权重。权重高的节点,被选中的次数就多。

举个例子:

# 假设三个报价源节点
节点A: 权重 5
节点B: 权重 3
节点C: 权重 2

# 每10个请求的分配模式
A A A A A  B B B  C C

我个人习惯用加权轮询来应对「异构集群」。比如你刚扩容了一批新机器,性能是老机器的两倍,那新机器权重设2,老机器设1,流量自然就倾斜过去了。

这里有个小技巧:权重不要设得太大。我见过有人把权重设成100、50、10这种跨度,结果流量分配非常不均匀。建议权重范围控制在1-10之间,颗粒度够用,也容易调整。

经验之谈:加权轮询的权重调整,最好配合监控数据来做。我一般看CPU使用率和请求延迟,如果某台机器延迟高了,就降权重,而不是直接摘掉它。

4.3 最少连接(Least Connections)—— 动态感知负载

最少连接,顾名思义,就是每次请求都发给当前活跃连接数最少的那个节点。

这个策略比轮询聪明一点。它不假设节点性能相同,而是实时感知每个节点正在处理多少请求。你想想看,如果某个节点处理得慢,它的活跃连接数就会堆积,新请求自然就不会再发给它了。

我在做实时报价系统时,特别喜欢用这个策略。因为报价请求的响应时间波动很大——有的请求100ms就回来了,有的可能要等2秒。如果用轮询,慢请求会堵在某个节点上;用最少连接,系统会自动把新请求分流到空闲节点。

核心优势:自动适应后端节点的处理能力差异,天然具备「慢节点保护」能力。

但要注意,最少连接需要维护每个节点的连接计数,这会带来额外的内存开销。对于高并发场景(每秒几万请求),这个计数器的更新和查询必须非常高效。我一般用原子操作或者无锁队列来实现,避免锁竞争。

避坑指南:我曾经遇到过一个情况——某个节点挂了,但连接还没断开,导致它的连接数一直不为0。新请求虽然优先发给其他节点,但这个死节点仍然在计数列表里。解决方案是加一个健康检查,连接数超过某个阈值就自动剔除。

4.4 一致性哈希(Consistent Hashing)—— 缓存友好的路由

一致性哈希,这个稍微复杂一点。它的核心思想是:把请求的某个特征(比如用户ID、报价ID)哈希到一个环上,然后顺时针找到最近的节点。

为什么要用这个?因为它在节点增减时,只会影响少量请求的路由。你想想看,如果用普通哈希取模,加一台机器,所有请求的路由都会变,缓存全部失效,这就是所谓的「缓存雪崩」。

我画了一张图,帮你理解一致性哈希的工作原理:

A 节点A B 节点B C 节点C D 节点D 请求1 请求2 请求3 顺时针查找 请求1 → 顺时针找到节点A 请求2 → 顺时针找到节点C 请求3 → 顺时针找到节点D

你看,每个请求根据它的哈希值落在环上,然后顺时针找到第一个节点。如果节点B挂了,原来路由到B的请求会顺延到C,只有这部分请求受影响,其他请求的路由不变。

我在做报价缓存系统时,就用了一致性哈希。每个报价源的请求根据报价ID哈希,同一个报价ID永远路由到同一个节点。这样缓存命中率极高,而且加节点时,只有少量缓存需要重建。

实践建议:一致性哈希要配合「虚拟节点」使用。每个物理节点在环上放多个虚拟节点,这样节点增减时,流量迁移更均匀。我一般每个物理节点放100-200个虚拟节点。

4.5 四种策略对比

说了这么多,咱们用一张表总结一下:

策略 核心思想 优点 缺点 适用场景
轮询 依次分配 实现简单,无状态 不考虑节点差异 同构集群,请求处理时间均匀
加权轮询 按权重分配 支持异构集群 权重需要手动调整 节点性能不同,但相对稳定
最少连接 动态感知负载 自动适应慢节点 需要维护连接状态 请求处理时间波动大
一致性哈希 哈希环路由 节点增减影响小 实现复杂,有哈希倾斜风险 需要缓存亲和性的场景

4.6 我的选型建议

说实话,没有银弹。我一般这样选:

  • 初期系统:用轮询,简单可靠,出问题容易排查。
  • 异构集群:加权轮询,配合监控动态调整权重。
  • 响应时间波动大:最少连接,比如实时报价、API网关。
  • 需要缓存亲和性:一致性哈希,比如报价缓存、会话保持。

最后说一句:不管你选哪种策略,一定要加「熔断」和「重试」机制。我见过太多系统,负载策略选得完美,结果一个节点挂了,重试请求全部打到另一个节点,直接把那个节点也打挂了。嗯,这就是所谓的「级联故障」。

核心原则:负载均衡策略解决的是「怎么分」的问题,但「分错了怎么办」要靠熔断、重试、限流来兜底。两者缺一不可。

公众号:蓝海资料掘金营,微信deep3321