负载均衡

凌晨 2 点,电商大促刚刚结束,运维群里突然炸了:某台后端服务器 CPU 被打满到 100%,接口响应时间从正常的 50ms 飙升到 5 秒,而其他两台服务器却悠闲地idle着。你紧急登录负载均衡器查看,发现问题根源是一个「看起来很合理」的配置——加权轮询权重设置为 4:2:1,但实际处理能力比例却是 1:1:1。更糟糕的是,由于会话保持策略,这台被"照顾"的机器上还堆满了长连接,GC 压力剧增,雪球越滚越大。

这个场景折射出负载均衡领域最典型的两类问题:流量分配策略选择不当会话保持机制的双刃剑效应。很多人以为负载均衡只是一个「把请求分到多台机器」的工具,但实际上,从算法选型、协议选择、健康检查到会话管理,每个环节都有深坑。

本模块将系统讲解负载均衡的核心知识,从四层到七层、从轮询到一致性哈希、从单机到全局,帮你建立完整的负载均衡知识体系。下次再遇到「流量倾斜」「服务雪崩」类的问题,你能快速定位根因并给出解决方案。

什么是负载均衡

负载均衡的核心目标很简单:将进入系统的请求合理分配到多个后端节点,使每台节点的负载保持在合理范围内,同时最大化系统整体吞吐能力。

但「合理分配」这四个字背后,涉及到流量分配算法、健康检查机制、会话管理策略等一系列复杂设计。一个配置失误,可能导致集群整体能力打个对折;一个策略不当,可能引发雪崩式的连锁故障。

三层模型

负载均衡按工作层级可分为三层:

层级位置职责典型技术
网络层传输层基于 IP/端口的流量分发LVS、DPVS、F5
应用层HTTP/S 协议层基于 URL/Header 的智能路由Nginx、HAProxy、Envoy
数据层数据库/缓存层数据分片与请求路由ShardingSphere、MySQL Proxy
flowchart TB
    subgraph Internet["互联网"]
        Client["客户端"]
    end

    subgraph L4["四层负载均衡(LVS/DPVS)"]
        L4LB["TCP/UDP 分发"]
    end

    subgraph L7["七层负载均衡(Nginx/HAProxy)"]
        L7LB["HTTP/S 路由"]
    end

    subgraph Backend["后端服务集群"]
        S1["服务节点 1"]
        S2["服务节点 2"]
        S3["服务节点 3"]
    end

    Client --> L4LB
    L4LB --> L7LB
    L7LB --> S1
    L7LB --> S2
    L7LB --> S3

三层模型的选择取决于业务场景:追求极致性能选四层,需要精细路由选七层,数据分片则需要在应用层或数据层处理。

四层 vs 七层负载均衡

这两者的本质区别在于协议解析深度转发性能的权衡。

维度四层负载均衡七层负载均衡
工作位置TCP/UDP 层HTTP/HTTPS 层
协议解析仅解析 IP + 端口解析 URL、Header、Cookie
转发方式基于连接的代理重新建立连接
性能极高(单实例百万级 CPS)较高(单实例十万级 CPS)
功能基础分发路径路由、重写、限流、认证
适用场景数据库、Redis、高并发短连接Web API、微服务网关

选择依据:如果只需要把请求均匀分到后端节点,选四层;如果需要根据请求内容做路由选择,选七层。两者也可以组合使用——四层做入口流量分发,七层做细粒度路由。

负载均衡算法

负载均衡算法是本模块的核心内容。从流量分配策略来看,算法可分为三大类:

静态算法

静态算法不考虑节点实时负载状态,仅根据预设规则分配流量。优点是实现简单、行为可预测,缺点是无法应对节点性能差异和实时负载波动。

算法描述适用场景
轮询(Round Robin)依次分发请求,循环往复节点性能一致
加权轮询(Weighted Round Robin)按权重比例分发节点性能不一致
随机(Random)随机选择节点负载波动小、节点数量多
加权随机(Weighted Random)按权重随机选择节点性能不一致

动态算法

动态算法会采集节点实时状态(连接数、响应时间等),选择当前负载最轻的节点。优点是能更好利用集群整体能力,缺点是实现复杂、状态采集有延迟。

算法描述适用场景
最小连接数(Least Connections)选择当前连接数最少的节点长连接场景
加权最小连接数(WLC)结合连接数与权重异构集群
最短响应时间(Least Response Time)选择响应时间最短的节点对延迟敏感的业务

哈希算法

哈希算法将某些特征(客户端 IP、请求参数等)映射到特定节点,保证相同特征的请求始终路由到同一节点。这对有状态服务至关重要。

算法描述适用场景
源 IP Hash基于客户端 IP 哈希无 Cookie 的简单会话保持
一致性哈希环结构 + 虚拟节点缓存集群、分布式哈希表

一致性哈希详解

一致性哈希是分布式系统中的核心技术,面试中的高频问题,也是缓存集群(如 Redis、Cassandra)广泛采用的路由算法。

环结构

传统哈希取模的问题是:当节点数量变化时,几乎所有键的映射关系都会改变,导致缓存大量失效。

一致性哈希的解决方案是引入环结构。将哈希空间组织成一个环,范围从 02^32 - 1,节点和数据都映射到这个环上,数据顺时针找到最近的节点。

flowchart RL
    subgraph Ring["一致性哈希环"]
        direction TB
        H0["0"]
        H1["2^32/4\n约10亿"]
        H2["2^32/2\n约21亿"]
        H3["3*2^32/4\n约32亿"]

        N1["节点A\n哈希值: 100"]:::node
        N2["节点B\n哈希值: 100"]:::node
        N3["节点C\n哈希值: 100"]:::node
        D1["数据K1\n哈希值: 80"]:::data
        D2["数据K2\n哈希值: 150"]:::data
        D3["数据K3\n哈希值: 280"]:::data
    end

    classDef node fill:#e1f5fe,stroke:#01579b
    classDef data fill:#f3e5f5,stroke:#4a148c

    H0 --> N1 --> N2 --> N3 --> H0
    N1 -.-> D1
    N2 -.-> D2
    N3 -.-> D3

虚拟节点

物理节点数量少时,环上的数据分布可能极不均匀。例如三个节点恰好哈希到相邻位置,某个节点可能承担 50% 的数据。

虚拟节点通过为每个物理节点创建多个虚拟副本(通常 150~200 个),使节点在环上均匀分布。当某节点宕机时,其负载会平滑转移到多个虚拟节点,降低单点压力。

指标无虚拟节点有虚拟节点(150个/物理节点)
节点下线影响单节点全部数据重新分布影响分散到多个节点
负载均衡度依赖哈希均匀性实际负载偏差 <10%
内存开销每节点增加少量路由表项

迁移量控制

节点变更时,一致性哈希的迁移量远小于传统哈希:

场景传统哈希迁移率一致性哈希迁移率
新增 1 节点n/(n+1) ≈ 100%1/(n+1) ≈ 33%
删除 1 节点1/n ≈ 50%1/n ≈ 33%

假设原来有 3 个节点,新增第 4 个节点后,传统哈希有 75% 的数据需要迁移,而一致性哈希只有约 25%。

健康检查机制

健康检查是负载均衡器的「眼睛」,负责判断后端节点是否存活、是否能够处理请求。

主动检查 vs 被动检查

类型原理优点缺点
主动检查负载均衡器主动探测节点状态提前发现问题增加网络流量
被动检查根据实际请求结果判断无额外开销故障已发生

协议类型

协议实现方式适用场景
TCP 检测尝试建立 TCP 连接通用场景
HTTP/HTTPS 检测发送 GET 请求,检查响应码Web 服务
自定义协议发送特定报文,验证响应特殊业务服务

检查参数设计

健康检查看似简单,但配置不当会引发两个问题:检查太频繁增加负载均衡器压力;检查间隔太长导致故障节点长时间未被摘除。

参数推荐值说明
检查间隔3~5s太短则资源消耗大,太长则故障发现慢
超时时间1~2s应小于检查间隔
成功阈值1~2次连续成功次数后才恢复
失败阈值3~5次连续失败次数后才摘除

会话保持与会话复制

无状态设计是分布式系统的最佳实践,但现实中总有例外。某些场景下,同一用户的请求必须路由到同一节点——这就是会话保持(Sticky Session)的需求。

三种实现方式

方式原理优点缺点
Cookie 重写在响应 Cookie 中写入节点标识客户端无需改造Cookie 暴露节点信息
Session 亲和性负载均衡器维护会话表可追溯增加内存开销
分布式 SessionSession 统一存储(Redis)节点无关增加网络延迟

七层负载均衡器可以在 HTTP 响应头中植入 Cookie,标记本次分配的节点。后续请求携带此 Cookie,负载均衡器解析后路由到对应节点。

# 请求 1: 用户首次访问,无 Cookie
GET /api/user HTTP/1.1
Host: example.com

# 响应: 负载均衡器植入 Cookie
HTTP/1.1 200 OK
Set-Cookie: SERVERID=node-02; Path=/; HttpOnly

# 请求 2: 用户携带 Cookie
GET /api/user HTTP/1.1
Host: example.com
Cookie: SERVERID=node-02

# 负载均衡器解析 Cookie,路由到 node-02

分布式 Session 方案

当服务需要水平扩展时,本地 Session 会成为瓶颈。常见方案是将 Session 集中存储到 Redis:

flowchart LR
    Client["客户端"] --> LB["负载均衡器\n无会话保持"]
    LB --> S1["服务节点 1"]
    LB --> S2["服务节点 2"]
    LB --> S3["服务节点 3"]
    S1 <--> Redis["Redis 集群\nSession 存储"]
    S2 <--> Redis
    S3 <--> Redis

这个方案的trade-off是:节点可以任意扩展,但所有请求都需要访问 Redis,网络开销增加约 1~2ms。如果 Redis 不可用,服务将无法获取 Session。

部署架构

负载均衡的部署位置决定其职责范围。从客户端到服务端,存在三种部署形态:

客户端负载均衡

负载均衡逻辑嵌入到客户端 SDK 中,客户端直接感知所有后端节点地址。典型实现如 Ribbon(已停止维护)、Spring Cloud LoadBalancer。

特点说明
优点无单点瓶颈,客户端可自定义路由策略
缺点客户端升级需要全量发布,策略分散难以统一管理

服务端负载均衡

负载均衡逻辑集中在一组专用节点(软件如 Nginx、HAProxy,或硬件如 F5)。客户端只需感知负载均衡器地址。

特点说明
优点策略集中管理,客户端轻量
缺点单层负载均衡器可能成为瓶颈

全局负载均衡(GSLB)

在多个机房或地域之间进行流量调度,结合 DNS 解析实现就近访问、故障切换。典型场景是「两地三中心」架构。

flowchart TB
    subgraph Global["全局负载均衡层"]
        DNS["DNS 服务器"]
        GSLB["GSLB 控制器"]
    end

    subgraph Region1["区域 1"]
        L47_1["四层负载均衡"]
        L7_1["七层负载均衡"]
        App1["应用服务"]
    end

    subgraph Region2["区域 2"]
        L47_2["四层负载均衡"]
        L7_2["七层负载均衡"]
        App2["应用服务"]
    end

    User["用户"] --> DNS
    DNS --> GSLB
    GSLB --> Region1
    GSLB --> Region2

GSLB 解决的问题是:如何让用户访问最近、最健康的机房? 这需要结合地理位置信息、健康状态、负载情况综合决策。

本章文章导读

负载均衡是一个涉及面极广的领域,从协议栈底层到应用层都有覆盖。以下是本模块的文章结构,建议按顺序阅读:

文章核心内容建议阅读人群
负载均衡概述基本概念、三层模型、选型依据入门必读
四层负载均衡(LVS/DPVS)LVS 架构、DR/NAT/Tunnel 模式基础设施工程师
七层负载均衡(Nginx/HAProxy)HTTP 协议处理、高级路由功能后端开发
轮询与加权轮询算法静态算法的实现与权重配置运维工程师
最小连接数与加权最小连接数动态算法的原理与实现架构师
IP Hash 与一致性哈希哈希算法详解、虚拟节点原理分布式系统开发者
最短响应时间算法算法设计与性能优化性能工程师
地理位置负载均衡(GSLB)DNS + 智能调度、就近访问多地域架构设计
客户端负载均衡Ribbon/Spring Cloud LB 实战Java 开发者
服务端负载均衡Nginx/K8s Ingress 配置运维/后端
健康检查机制主动/被动检查、阈值设计可靠性工程师
会话保持Cookie 重写、分布式 Session全栈工程师
全局负载均衡与灾备多活架构、故障切换策略架构师

如果你已经有了明确的学习目标,可以直接跳转到对应文章。如果你是第一次接触负载均衡,建议从负载均衡概述开始,建立基本认知后再深入各个细分主题。

常见问题

Q:四层负载均衡一定比七层快吗?

不一定。LVS 的性能上限确实比 Nginx 高,但在现代硬件条件下,Nginx 单实例能轻松处理十万级 CPS,对大多数业务已经足够。七层负载均衡的协议解析能力在微服务场景下是刚需,不应为了「更快」而放弃。

Q:一致性哈希的虚拟节点数量怎么定?

经验值是 150~200 个/物理节点。这个数值在负载均衡度和内存开销之间取得了较好平衡。如果集群规模大(数十个节点),可以适当减少;如果节点异构性高(性能差异大),可以增加高性能节点的虚拟节点数。

Q:健康检查间隔设为多少合适?

这取决于业务对故障敏感度要求:

  • 金融交易类:2~3s,快速发现快速切换
  • 普通 Web 服务:5~10s,避免网络抖动误判
  • 长连接场景:30s+,基于应用层心跳检测

Q:会话保持一定要用吗?

尽量不用。会话保持会破坏负载均衡的均匀性,引发流量倾斜。优先考虑无状态设计,或者使用分布式 Session 将状态外置。