#DevOps

负载均衡策略:轮询/最少连接/一致性哈希

请求来了分给哪个后端?负载均衡器决定了分配策略。本文讲清 L4(网络层)vs L7(应用层)、常见算法(轮询/加权/最少连接/IP哈希/一致性哈希)各自适用、健康检查与会话保持、以及 Nginx/ALB/Envoy 等工具选型。

本文要点

  • 主题聚焦:DevOps
  • 适合人群:独立开发者、全栈工程师、AI 应用开发者
  • 核心价值:快速理解背景、实践路径、常见误区和工程建议
作者 @admin·发布于 2026年3月15日·更新于 2026年7月23日

负载均衡策略:轮询 / 最少连接 / 一致性哈希

一台 8 核 32G 的应用服务器,扛到 5000 QPS 就开始抖动,CPU 飙到 90%,GC 停顿拉长,P99 延迟从 50ms 飙到 800ms。你加内存、调 JVM 参数、优化 SQL,边际收益越来越小。这时候真正的问题不在单机性能,而在单机这个模型本身已经到头了。

解法很朴素:加机器。三台各扛 2000 QPS,比一台硬扛 6000 QPS 稳得多,还顺带拿到了容错——挂一台还有两台顶。

但加完机器立刻冒出新问题:用户的请求来了,分给哪一台? 这就是负载均衡器(Load Balancer,LB)要解决的事。它不只是"均匀分配"那么简单,选错策略,会出现有的机器被打爆、有的机器在摸鱼;缓存命中率雪崩;用户登录态丢失;扩容瞬间流量迁移把集群拖垮。这篇把负载均衡的关键决策点一次讲透。

一、为什么必须有负载均衡

负载均衡器在客户端和后端服务之间加了一层,它做三件事:

  1. 分发:把请求按某种策略分到多个后端实例,水平扩展能力。
  2. 健康:持续探活后端,挂掉的自动摘除,用户无感。
  3. 收敛:对外只暴露一个入口(VIP / 域名),后端扩缩容对客户端透明。

没有 LB 的"多机"只是几台孤立的机器;有 LB 才是真正可运维的集群。几乎所有现代架构,从一台 Nginx 到全球级 GSLB,都建立在这套抽象上。

二、L4 vs L7:在 TCP 那一层切开,还是在 HTTP 那一层切开

负载均衡器按工作层级分两大类,这是最根本的选型决策。

L4(传输层负载均衡):只看 IP + 端口,把 TCP 连接转发出去,不看也不解 HTTP 内容。代表:HAProxy 的 tcp 模式、LVS、云厂商的 NLB、IPVS。

  • 优点:极快,几乎只是改包头做转发,吞吐可以做到几十万 PPS;协议无关,MySQL、Redis、gRPC 都能转。
  • 缺点:看不到 URL、Header、Cookie,没法按路径路由,也没法做基于 HTTP 的灰度。

L7(应用层负载均衡):终结 TCP,把 HTTP 请求读出来,基于 URL、Header、Cookie、甚至请求体做路由决策。代表:Nginx、HAProxy 的 http 模式、云厂商的 ALB、Envoy。

  • 优点:灵活——/api/* 走 Java 集群,/static/* 走 CDN 回源,带 X-Canary: true 的请求灰度到新版本;能改写请求、压缩、限流、WAF。
  • 缺点:重。每个连接要解析 HTTP,延迟和 CPU 开销都高于 L4;协议绑死(基本就是 HTTP/HTTPS)。

实战经验:入口层用 L7(要 HTTPS 卸载、要路径路由、要灰度),内层服务间通信用 L4(要吞吐、要协议无关)。这是绝大多数中大型系统的默认分层。

三、五大算法:请求到底分给谁

这是 LB 最核心的策略。选对算法,集群利用率均匀、延迟低;选错,要么打爆单机,要么缓存全废。

1. 轮询(Round Robin):A→B→C→A→B→C,依次分配。简单、长期看均匀,适合所有后端机器配置相同、每个请求处理成本接近的场景。坑:如果请求成本差异大(有的查缓存 1ms,有的跑大 SQL 500ms),轮询会让某些机器偶然堆一堆慢请求。

2. 加权轮询(Weighted Round Robin):给每台机器一个权重,按权重比例分配。8 核机器权重 2,4 核机器权重 1,于是 8 核的分到 2 倍请求。适合机器配置不一致(混合机型、新老并存),也用来做灰度——新版本权重从 1 慢慢调到 100。Nginx 的默认算法就是平滑加权轮询(Smooth WRR),让权重分配在时间上更均匀,不会突发。

3. 最少连接(Least Connections):把请求分给当前活跃连接数最少的那台。这是最"智能"的简单算法,天然应对请求成本不均:慢请求多的机器连接数高,新请求就自动绕开它。适合请求处理时间差异大(API 网关、长连接、WebSocket、文件上传)。代价:LB 要维护每台后端的连接计数,有状态,但对现代 LB 不是问题。HAProxy 的默认就是 leastconn。

4. IP 哈希(IP Hash):对客户端 IP 做哈希,映射到固定后端。同一个客户端总是落到同一台机器。这本质是为了会话保持(见第五节)——session 存在本地内存里时,必须让同一用户回同一台。坑:哈希分布不一定均匀(某些大 NAT 出口的 IP 流量巨大,会打爆一台);加减节点时,几乎所有用户的映射都变了,session 全失效。

5. 一致性哈希(Consistent Hash):把后端和请求都映射到一个环上,请求顺时针找最近的节点。关键性质:加减节点时只有该节点相邻区间的请求会迁移,其他不变。迁移量 ≈ 1/N(N 为节点数),远好于普通哈希的几乎全迁。适合缓存层(Redis Cluster、Memcached、CDN 回源),因为缓存失效等于穿透打到 DB。常配合"虚拟节点"让分布更均匀。

算法对比一览:

算法核心逻辑最适合主要坑
轮询依次分同质机器、等成本请求慢请求堆积不均
加权轮询按权重分异构机型、灰度发布权重需手动维护
最少连接分给连接最少的请求耗时差异大LB 需维护连接状态
IP 哈希同 IP 固定后端本地 session 保持分布不均、扩容全乱
一致性哈希环上就近缓存层、扩缩容频繁需虚拟节点均衡

一个实操判断:默认拿「最少连接」起步,它对真实流量的适应性最好。只有当你有明确的会话保持或缓存亲和需求时,才上 IP 哈希 / 一致性哈希。

四、健康检查:挂了要能自动摘掉

LB 的另一项核心职责是只把流量分给健康的后端。没有健康检查,挂掉的机器会持续收到请求,LB 把超时当正常分发,用户看到的就是"半个集群故障"。

两种模式:

被动健康检查:LB 不主动探测,只看真实请求的结果。连续 N 次失败就标记该后端为 down,暂停分发;过一段时间再试。优点:零额外流量;缺点:用户请求是探针,恢复时第一批请求会失败。HAProxy、Nginx 默认支持。

主动健康检查:LB 定期向后端发探针(HTTP GET /health 或 TCP connect),根据响应决定健康状态。能更早发现故障,且不依赖真实流量。Nginx 开源版只有简化版,Nginx Plus / HAProxy / ALB / Envoy 都有完整主动探活。代价:后端要提供一个轻量、无副作用的健康端点,且别让探针本身成为负担(别在 /health 里查 DB)。

生产实践:两者都用——被动检查负责秒级失败隔离,主动检查负责周期性确认和恢复。健康端点要分层:liveness(进程活着)和 readiness(依赖就绪,能接流量)分开,DB 没连上时 readiness 应返回 503,让 LB 暂时摘除。

五、会话保持:同一用户回同一台

很多服务还是有状态的:session 在本地内存、本地文件缓存、WebSocket 长连接绑在某个进程。这些场景要求同一用户(或同一连接)始终落到同一台后端,这就是 Sticky Session(会话保持)。

实现方式:

  • IP 哈希:上面讲过,粗粒度,问题是大 NAT 出口背后成千上万用户共用一个 IP,会被压到一台。
  • Cookie 粘性:LB 在首次响应里种一个 Cookie(如 SERVERID=node3),后续请求带这个 Cookie 就回 node3。HAProxy、Nginx、ALB 都支持,粒度细,是主流方案。
  • Header / 业务字段:按用户 ID、租户 ID 做一致性哈希,适合多租户 SaaS。

代价明确:后端挂了,粘在那台的用户的 session 会丢(除非 session 存外部 Redis)。所以会话保持是"必要的恶"——更优的架构是把状态外移(Redis、JWT),让后端无状态,任意机器都能接任意请求,这才是真正自由的水平扩展。能用无状态就别用 Sticky。

六、工具选型:Nginx / ALB / HAProxy / Envoy

工具定位典型场景
Nginx通用 L7(也支持 L4 stream),生态最广入口反代、HTTPS 卸载、静态资源、中小集群 LB。绝大多数团队的默认选择
AWS ALB / 云厂商 L7 LB托管 L7,深度集成 VPC、IAM、证书、WAF云原生架构、不想自己运维 LB 实例、按 LCU 付费
HAProxy高性能 L4/L7,配置精细,连接管理强性能敏感的入口、L4 TCP 负载、数据库前置代理
Envoy现代 L7,Sidecar / 服务网格核心微服务网格(Istio 基于它)、gRPC、可观测性要求高

选型思路:云上要省心→ ALB;要控制力 + 性价比→ Nginx 自建;追求极致性能 / L4→ HAProxy;微服务网格化→ Envoy。大公司内部往往是多层叠加,不二选一。

七、多层均衡:大型架构是"洋葱"

真正高可用的系统,负载均衡不止一层,而是从外到内层层收敛:

  • 全局层(GSLB / DNS):按地理、按运营商把 www.example.com 解析到最近的区域。用户在北京就回北京机房的 VIP,在东京就回东京的。Anycast / GeoDNS 实现。
  • 区域层(L7 ALB / Nginx):机房入口,做 HTTPS 卸载、按 URL 路由到不同服务(/order 走订单集群,/search 走搜索集群)、按 Header 灰度。
  • 服务层(L4 / Sidecar):服务内部实例间,按连接或请求分发,通常 L4 走 NLB/IPVS,或 Service Mesh 的 Envoy Sidecar 做精细 L7。

三层各司其职:全局扛地域级故障(某机房整体宕机),区域做业务路由和灰度,服务层做实例级负载均衡和健康隔离。没有哪一层能独立解决所有问题——单层 L7 ALB 扛不住跨地域,单层 DNS 又做不了 HTTP 灰度。洋葱式的分层,才是大系统应对"任何一层都可能挂"的现实之道。

小结

  1. 负载均衡器解决三件事:分发流量、健康隔离、收敛入口。没有它,"多机"只是孤立机器。
  2. L4 看 IP/端口、快但笨;L7 看 HTTP、灵活但重。入口用 L7,内层用 L4,是绝大多数系统的默认分层。
  3. 算法默认选最少连接,它对真实流量(请求耗时不均)适应性最好;缓存层才用一致性哈希,会话保持才用 IP 哈希 / Cookie。
  4. 健康检查被动 + 主动双保险,健康端点 liveness 与 readiness 分开,别在探针里查 DB。
  5. 会话保持是必要的恶,最优解是把状态外移让后端无状态;大型系统走多层均衡(GSLB → L7 → L4)层层收敛。

金句:负载均衡不是选一个最强的算法,而是让每一层只做自己擅长的事——入口懂业务,内层懂吞吐,全局懂地理。 把决策分到对的层,比在任何一层追求完美都重要。

Related

相关推荐