负载均衡算法深度实战:在 Nginx/HAProxy 上做好加权、最少连接与会话保持


很多自托管架构最后都会卡在同一个问题上:后端有两个甚至更多实例,流量进来到底发给谁?"第一个先回"听上去简单,但真实的负载不均、某台慢拖全队、会话状态跟随错台……都会让"简单的负载均衡"变成"头秃的负载均衡"。"把请求分发给哪个后端"这件事,看似小,实则由一整套算法决定:轮询、加权轮询、最少连接、IP Hash/一致性哈希、会话保持等。这篇讲清这些算法各解决什么、该怎么选、在 Nginx/HAProxy 上怎么落地,以及常见坑与边界。

一、负载均衡算法解决什么:不止是"平均分",而是"合理分担 + 稳定可靠"

负载均衡的初衷是把流量散到多个后端,让没人被压垮。但"平均分"只是最低要求:后端的性能往往不同(一台新一台旧)、请求的代价不同(A 简单 B 重)、有的服务要求"同一个用户的请求始终落到同一台"。不同算法回应的是不同诉求:轮询管"简单横分",加权轮询管"性能不均的后端按能力分",最少连接管"请求耗时不均、谁闲给谁",IP 哈希/一致性哈希管"同一来源始终到同一台(利于缓存与状态)"。选算法的本质,是回答"你想让分发照顾哪一个特征:均匀、能力、实时负载、还是稳定性"。

它和前面聊的"高可用"不同但互补:高可用回答"某台挂了流量不能丢",负载均衡回答"多台都在时请求该往哪发"。两者配合才是"多副本被用得既均匀又可靠"。而"会话保持"(session affinity/sticky session),则是在负载均衡之上加的"让同一会话留在同一后端"的约束——对某些带本地状态的应用是刚需。

二、几种主流算法各适合什么:轮询/加权/最少连接/哈希

用一张表就能看清主算法与它们的取舍。轮询(round-robin):依次轮流,适合后端性能相近、请求代价相近的时候,实现最简单。加权轮询(weighted):给高性能后端配更大权重(如 3:1),让它接更多流量,适合性能不均但大体稳定。最少连接(least_conn):把新请求发给"当前活跃连接最少"的后端,适合请求耗时差异大、连接数能反映真实负担的场景。IP 哈希(ip_hash / IP Hash):同一来源 IP 的请求固定到同一台,利于无共享缓存/本地会话,但会放大单来源倾斜、后端增减时也会打乱映射。

# Nginx upstream 示例:加权轮询 + 最少连接 + 备份节点
upstream backend {
  # 加权:web1 性能好权重 3,web2 权重 1
  server 192.168.1.10:80 weight=3;
  server 192.168.1.11:80 weight=1;
  # 最少连接:在满足权重的前提下,优先发给活跃连接最少的
  least_conn;
  # 备份:其他都挂时才用
  server 192.168.1.12:80 backup;
}
# HAProxy 类似:
#   balance roundrobin
#   balance leastconn
#   balance source   (按源IP哈希,利于会话保持)

选择建议很务实:先从"轮询"起步观察,若发现某台忙不均就上"加权";若请求耗时不均就上"最少连接";若有本地缓存/会话、且后端不共享,才用"哈希 + 会话保持"。别一上来就堆最复杂的一套——复杂度高的算法要求更多的观测与排障投入。

三、会话保持与一致性哈希:什么时候需要"同一来源始终到同一台"

有些应用把会话/临时数据放在实例本地(内存里的 session、本地进程缓存),此时"同一个用户的两请求落到不同后端"会导致状态错乱——需要会话保持。会话保持实现方式多样:Nginx/HAProxy 可用"IP 哈希"或"cookie 固定下发"(sticky cookie),让同一会话绑定同一后端。另有一致性哈希:用于缓存/DNS 这类场景,保证后端变动时映射尽量少地被打乱,减少缓存大面积失效。要点是"会话保持解决本地状态,但代价是负载可能不均(某台被热点独占)"——要权衡。

# Nginx:按 IP 哈希(同一 IP 尽量到同一台,带本地会话时用)
upstream backend {
  ip_hash;
  server 192.168.1.10:80;
  server 192.168.1.11:80;
}
# HAProxy:用 cookie 做 session 持久化(给用户发 cookie 记住后端)
#   cookie SRV insert indirect nocache
#   server web1 192.168.1.10:80 cookie web1
#   server web2 192.168.1.11:80 cookie web2

会话保持的坑是"热点失衡":一旦某 IP/某 cookie 集中,该后端可能被独占而其他后端闲置。因此选会话保持的前提是"确实需要本地状态",否则能用无状态 + 共享存储(Redis/Session 外置)就把状态拿出来、不需要会话保持,更均匀也更稳。这通常比"固定分配到某台"更推荐——架构上无状态了,负载均衡才真正自由。

四、常见坑:健康检查、后端增减打乱哈希、加权看平均数、会话抖动

负载均衡跑起来,四个坑要防。一是"缺健康检查":只配 server 不配 check,某台挂了你还在往它发请求,大量 5xx 却怪算法不行——Nginx 用 passive 主动探测、HAProxy 用 `check` 明确配好探活,下掉不健康的节点。二是"后端增减哈希错乱":IP 哈希/一致性哈希在后端数量变化时映射会大量重排,导致缓存/会话大量转移——一致性哈希缓解增量变化,规模变动要有平滑策略。三是"只看平均数":加权轮询的权重是"期望"不是"实时",突发流量下仍可能不均,要用 least_conn 或用监控看真实分布。四是"会话抖动":后端滚动升级/重启会断会话保持,搭配"无状态化 + 共享会话存储"才能让滚动升级不把用户踢下线。

# HAProxy 必配健康检查,挂了自动摘除
backend web
  balance leastconn
  option httpchk GET /health
  server web1 192.168.1.10:80 check inter 3s fall 3 rise 2
  #                    ↑ 每3秒探一次,连挂3次摘除,恢复2次加回

把这当排障 SOP:先看"该后端的健康检查是否 up、流量是否真的发出去了",再看"算法是否适合当前负载特征(看各后端连接数分布)",再确认会话保持/哈希是否造成热点或断连。负载均衡的问题多数不在算法本身,而在"健康检查没配、状态该外置却做了会话保持"。

五、边界:算法分担"请求",不解决后端本身的性能与一致性

负载均衡算法的边界要认清:它把请求合理地分发下去,但改变不了"后端的绝对性能"(后端本身慢,分给谁都慢),也不解决"无共享状态被逃逸"带来的数据一致问题——那是架构上把状态外置(数据库/缓存)的职责。其次,算法是运维参数而非万能键:没有监控和流量数据支撑的空想配置,往往是不均和难排障的根源。最后,别为了"看起来高级"而堆复杂度,简单算法 + 可靠健康检查 + 把状态外置,往往比复杂的哈希 + 本地状态更省心也更稳。

把负载均衡算法放回自托管整体:它决定"多副本后端之间的流量怎么分",是高可用与横向扩展的落地细节。落地要点:按负载特征选算法——性能相近用轮询、能力不均用加权、耗时不等用最少连接、有本地状态才用哈希/会话保持(且最好首先把状态外置);配好健康检查(Nginx/HAProxy 的 check 探活、自动摘除与恢复);防住缺健康检查、后端增减哈希错乱、只看权重均数、会话抖动四坑。认清它分担的是请求而非后端性能与一致性。当你把"算法合适 + 健康检查可靠 + 后端尽量无状态"这套吃透,多副本才算真正被用得又均匀又省心。

结语

负载均衡算法的价值,是决定"一堆后端之间的流量往哪发、怎么发才既均匀又可靠"。落地要点:轮询管简单横分、加权管能力不均、最少连接管耗时不均、IP 哈希/一致性哈希 + 会话保持管"同源同台",多数自托管从轮询起步、据观测逐步加权/最少连接;能无状态就先外置状态(数据库/Redis),别让会话保持制造热点;任何算法都要配健康检查(`check` 探活、自动摘除),并防住后端增减哈希错乱、只看权重、会话抖动四坑。认清算法分担的是请求而非后端性能与一致性——当算法与健康检查配合得当、后端多已无状态,自托管的横向扩展才真正从"能多开"变成"开得稳"。


手机扫码阅读

微信或手机浏览器扫一扫,随时随地随心阅读与分享

Keycloak 统一身份认证实战:用 OIDC/SSO 把散落账号收拢成一个身份中心

镜像签名与供应链安全实战:用 Sigstore/cosign 让镜像可验证可追溯

评 论
更换验证码