逆风的蚂蚁头像

服务器负载均衡怎么落地?我把轮询、最少连接和一致性哈希这三种分发逻辑用 Python 跑了一遍

服务器负载均衡不是把流量「平均切成三份」那么简单。我这次用 Python 起了三台模拟后端,把轮询、最少连接和一致性哈希三种分发逻辑逐个跑了一遍,用真实落点数而不是文档口号来说话。

环境声明:以下代码与输出均在 Windows 10 + Python 3.13.14 本机跑出,三台后端为本地 127.0.0.1 上的 socket 服务,延迟靠 time.sleep 模拟;云平台相关命令与控制台操作为官方文档依据,未接云实测。

先分清楚:你要的是「均匀撒」还是「谁闲给谁」

理解服务器负载均衡,先分清三类目标,因为三类目标用的是完全不同的算法,混着选就会出问题:

  • 均匀撒:不关心后端快慢,按固定顺序一人一个,追求的是「条数公平」。
  • 谁闲给谁:盯着每台后端的在途连接数,永远挑更空的那台,追求的是「不把慢节点压垮」。
  • 同客同节点:同一个客户端(或同一个会话 key)必须落到同一台,追求的是「会话不串」。

我下面的实测就按这三档分别跑,每一档都给真实计数,而不是只抛名词。

轮询(round-robin):不看后端死活,一人一个

轮询是服务器负载均衡里入门的一档算法,逻辑简单:维护一个自增下标,每来一个请求就 +1 然后取模。它完全不感知后端是快是慢、是死是活(死活交给健康检查管,后面会讲)。

我用三台后端(A、B 两台快节点各 0.01s,C 一台慢节点 0.2s),以每 10ms 一个的稳态节奏发了 30 个请求:

[round-robin] 并发 30 请求,总耗时 1.521s
  nodeA   分到 10 次  (delay=0.01s)
  nodeB   分到 10 次  (delay=0.01s)
  nodeC   分到 10 次  (delay=0.2s)
  分布: {'nodeA': 10, 'nodeB': 10, 'nodeC': 10}

关键看慢节点 nodeC:它拿了和快节点一样多的 10 个。轮询只认「顺序」,不认「能力」。在节点同构、无状态的服务里这没问题;一旦某台被慢查询拖住,轮询照样把等量请求塞给它,慢节点就排队去了。

最少连接(least-conn):盯着谁更闲,慢节点自然少分

最少连接算法每次选「当前活跃连接数最少」的后端。我用的选择逻辑是:读所有后端的 active,取最小值,并列时随机选一个,避免永远偏袒下标靠前的节点。

同一组后端、同样的 30 个稳态请求,换成最少连接:

[least-conn] 并发 30 请求,总耗时 1.530s
  nodeA   分到 12 次  (delay=0.01s)
  nodeB   分到 14 次  (delay=0.01s)
  nodeC   分到  4 次  (delay=0.2s)
  分布: {'nodeA': 12, 'nodeB': 14, 'nodeC': 4}

慢节点 nodeC 从轮询的 10 个掉到 4 个。原因很直白:它的 active 在请求在途期间一直偏高,选择器几乎不会选它。我提醒一句——最少连接解决的是「慢节点过载」,不是「均匀分配」;当后端速率差异极小、且请求是瞬时突发时,active 往往还没来得及累加就被读到 0,这时它和轮询表现差不多。生产环境里常配合「加权」:给强机器更大的权重,弱机器少分。

一致性哈希:同一个 key 永远落到同一台

一致性哈希是服务器负载均衡里为会话保持而生的算法。轮询和最少连接都会让同一个客户端的两次请求落到不同后端,这对「有状态会话」是灾难。一致性哈希用 hash(key) % N 把 key 钉在固定节点上。我拿 userA / userB / userC 各发 5 次:

userA -> 固定落在 nodeC
userB -> 固定落在 nodeC
userC -> 固定落在 nodeB
分布: {'nodeC': 10, 'nodeB': 5}

同一个 key 反复请求,落点不变——这就是会话保持的基础。我也如实说清楚:只有 3 个桶时,3 个 key 的取模结果天然不均(nodeA 一票没拿到),这不影响「同 key 同节点」该属性,但提醒你节点数很少时别指望它顺带做均匀分发。真实系统用带虚拟节点的哈希环来兼顾「稳定」和「均衡」。

光有算法不够:健康检查把死节点踢出去

算法再好,后端挂了还往里发就是事故。健康检查的做法是负载均衡器周期性去连后端(TCP 探测或 HTTP 探活),连不上就把它移出可用池。我把 nodeC 直接关掉再探一次:

探测前: [('nodeA', True), ('nodeB', True), ('nodeC', True)]
摘掉 nodeC 后存活: ['nodeA', 'nodeB']

[health-check后轮询] 并发 15 请求
  nodeA   分到  8 次
  nodeB   分到  7 次
  nodeC   分到  0 次
  死节点 nodeC 是否被分到: False

死节点 nodeC 分到 0,流量全部分到存活的两台。我特意验证过:即便算法仍按旧池子选,健康检查这一层也能在派发前把死节点挡掉。这里有个反直觉点——健康检查本身有间隔,节点刚挂的那几秒仍可能收到少量请求,所以后端自身也要有快速失败(fail-fast)而不是干等超时。

云上三家怎么做:内核还是这几样

讲到落地,三家云的做法内核一致,只是叫法和默认项不同,我按官方文档列一下:

厂商产品支持的均衡算法健康检查
阿里云负载均衡 SLB / ALB加权轮询、加权最小连接数、一致性哈希等TCP/HTTP/HTTPS 探活,异常自动隔离
腾讯云负载均衡 CLB加权轮询、IP Hash、加权最小连接数监听后端状态,异常实例停止路由
华为云弹性负载均衡 ELB轮询、最少连接、源 IP 哈希等健康检查异常自动隔离

我引的文档:阿里云负载均衡官方文档、腾讯云CLB 产品概述、华为云ELB 健康检查异常排查,以及 nginx 的upstream 模块手册(反向代理自己搭负载均衡时的配置范本)。三家都支持上面跑过的轮询、最少连接和哈希,差异主要在监听器模型、跨可用区行为和计费粒度上,选哪家看既有栈和地域,不必神话某一家。

什么时候不该上负载均衡

我列几条反向边界,省得为了「高可用」三个字硬上:

  • 单体单实例、无横向扩展需求:背后只有一台机器,前面挂负载均衡只是多了个单点,毫无意义。
  • 状态全在本地内存:如果你的会话存在进程内存而不是共享存储,哈希环一扩缩容,大量 key 重新映射,会话集体失效。
  • 吞吐瓶颈在数据库:加再多应用层负载均衡,后端都堵在同一个慢库上,分发再均匀也救不了延迟。
  • 小流量且变更频繁:维护健康检查阈值、权重、会话保持策略的运维成本,可能高过它带来的可用性收益。

上负载均衡前,我按这张清单核对

  • 后端是否无状态,或会话已外置(Redis 等)——决定能不能用轮询/最少连接。
  • 是否需要会话保持——需要就用哈希或源 IP 亲和,不需要就别开,避免热点。
  • 健康检查用 TCP 还是 HTTP,阈值(间隔、超时、连续次数)按后端启动时间定,别把冷启动判死。
  • 慢节点是否要加权,避免最少连接退化成「全压单台强机器」。
  • 跨可用区部署后端,单可用区故障能自动切走。
  • 探活端口和业务端口是否分开,别让健康检查请求污染业务指标。

FAQ

负载均衡和反向代理是一回事吗?
不是。负载均衡专注「把流量分发到多台后端」,反向代理还能做 TLS 终止、缓存、重写;nginx 的 upstream 模块就是拿反向代理顺手实现负载均衡,两者常结合使用。

轮询和最少连接怎么选?
后端同构、无状态、追求简单,选轮询;后端机型不一或有慢查询风险,选最少连接并配合权重。我实测里慢节点在轮询下拿了等量 10 个,在最少连接下只拿 4 个,差距就在这。

一致性哈希解决了什么问题?
解决「同一个客户端反复落到不同后端」导致的会话丢失。它用 key 的哈希把请求钉在固定节点,扩缩容时靠虚拟节点环减少对已有 key 的扰动。

健康检查间隔设多长合适?
按后端正常启动耗时定:间隔太短会把冷启动判死,太长则故障切换慢。一般取「启动时间 + 安全余量」,连续失败次数设 2–3 次再摘节点,避免抖动误伤。

结尾:从算法到落地的一条线

服务器负载均衡的本质,是先想清楚要「均匀撒」「谁闲给谁」还是「同客同节点」,再选轮询、最少连接或一致性哈希;算法负责分发,健康检查负责把死节点挡在门外,云上三家产品内核都是这几样,差异只在监听器模型和计费。我把三台本地后端跑出的真实计数摆在这里:轮询给慢节点 10 个、最少连接只给 4 个、哈希把同 key 钉死、摘节点后死节点分到 0——这些数字比任何「高可用」口号都实在。具体阈值与产品行为以各家官方文档当期说明为准。

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/2601_97101189/article/details/170346449

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--