强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

06 - 负载均衡 / Load Balancing

负载均衡 / Load Balancing

🟢 基础 / Basics — upstream 基本配置

最简配置

# 定义上游服务器组
upstream backend {
    server 192.168.1.10:3000;
    server 192.168.1.11:3000;
    server 192.168.1.12:3000;
}

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://backend;    # 引用 upstream
    }
}

默认情况下,Nginx 使用 加权轮询(Weighted Round Robin) 算法分配请求。

四种负载均衡算法

# 1. 轮询(Round Robin)— 默认
upstream backend {
    server 192.168.1.10:3000;
    server 192.168.1.11:3000;
    # 请求按顺序轮流分配: A → B → A → B → ...
}

# 2. 加权轮询(Weighted Round Robin)
upstream backend {
    server 192.168.1.10:3000 weight=3;    # 接收 3/4 的请求
    server 192.168.1.11:3000 weight=1;    # 接收 1/4 的请求
}

# 3. IP Hash — 同一客户端 IP 始终访问同一后端
upstream backend {
    ip_hash;
    server 192.168.1.10:3000;
    server 192.168.1.11:3000;
    # 203.0.113.50 始终访问 server 10
    # 198.51.100.30 始终访问 server 11
}

# 4. 最少连接(Least Connections)
upstream backend {
    least_conn;
    server 192.168.1.10:3000;
    server 192.168.1.11:3000;
    # 新请求分配给当前活跃连接最少的服务器
}

算法选择指南

算法适用场景优点缺点
轮询通用,后端性能一致简单公平不考虑后端负载差异
加权轮询后端性能不同按能力分配权重需手动调整
IP Hash需要会话保持无需分布式 Session后端增减时会话打散
最少连接请求处理时间差异大自适应负载需要更多计算

🟡 进阶 / Intermediate — 生产级负载均衡

服务器状态标记

upstream backend {
    server 192.168.1.10:3000 weight=3;
    server 192.168.1.11:3000 weight=2;
    server 192.168.1.12:3000 backup;        # 备用服务器,其他全挂时才启用
    server 192.168.1.13:3000 down;          # 标记为不可用(手动下线)

    # 连接数限制
    server 192.168.1.14:3000 max_conns=100; # 最多 100 个并发连接

    # 失败重试
    server 192.168.1.15:3000 max_fails=3 fail_timeout=30s;
    # 30 秒内失败 3 次,标记为不可用 30 秒
}
服务器状态机:

                 ┌──────────┐
     请求 ──────►│  Active  │◄──── 正常处理请求
                 └────┬─────┘
                      │ 失败次数达到 max_fails
                      ▼
                 ┌──────────┐
                 │  Failed  │     不接受新请求
                 └────┬─────┘
                      │ fail_timeout 超时后
                      ▼
                 ┌──────────┐
                 │  Active  │     恢复接收请求
                 └──────────┘

手动下线:  server ... down;
手动恢复:  去掉 down 标记,nginx -s reload

健康检查 / Health Check

被动健康检查(开源版):

upstream backend {
    server 192.168.1.10:3000 max_fails=3 fail_timeout=30s;
    server 192.168.1.11:3000 max_fails=3 fail_timeout=30s;

    # 当后端返回以下状态码时,视为失败
    # 配合 proxy_next_upstream 使用
}

server {
    location / {
        proxy_pass http://backend;
        proxy_next_upstream error timeout http_500 http_502 http_503;
        proxy_next_upstream_tries 2;
    }
}

主动健康检查(Nginx Plus 或 nginx_upstream_check_module):

# 使用第三方模块 nginx_upstream_check_module
# 需要编译时添加该模块

upstream backend {
    server 192.168.1.10:3000;
    server 192.168.1.11:3000;

    check interval=5000 rise=2 fall=3 timeout=1000 type=http;
    check_http_send "GET /health HTTP/1.0\r\n\r\n";
    check_http_expect_alive http_2xx http_3xx;
}

会话保持 / Session Persistence

# 方式 1:IP Hash(最简单)
upstream backend {
    ip_hash;
    server 192.168.1.10:3000;
    server 192.168.1.11:3000;
}

# 方式 2:Cookie Hash(更精确)
upstream backend {
    hash $cookie_sessionid consistent;   # 一致性哈希
    server 192.168.1.10:3000;
    server 192.168.1.11:3000;
}

# 方式 3:路由参数
upstream backend {
    hash $arg_user_id consistent;
    server 192.168.1.10:3000;
    server 192.168.1.11:3000;
}

一致性哈希 / Consistent Hashing

upstream backend {
    hash $request_uri consistent;    # 基于 URI 的一致性哈希
    server 192.168.1.10:3000;
    server 192.168.1.11:3000;
    server 192.168.1.12:3000;
}
一致性哈希的优势:

普通哈希:
增减服务器 → 所有请求的映射关系全部改变 → 缓存全部失效

一致性哈希:
增减服务器 → 只有 1/n 的请求映射改变 → 大部分缓存保持有效

         ┌─── Node A (192.168.1.10)
         │
环形空间 ─┼─── Node B (192.168.1.11)
         │
         └─── Node C (192.168.1.12)
         
请求按 hash 值落到环上,顺时针找到第一个节点

地理位置分流

# 使用 GeoIP2 模块(需要安装 libnginx-mod-http-geoip2)

geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
    auto_reload 60m;
    $geoip2_country_code country iso_code;
}

map $geoip2_country_code $backend_pool {
    default    domestic_backend;
    CN         domestic_backend;
    US         us_backend;
    EU         eu_backend;
}

upstream domestic_backend {
    server 10.0.1.10:3000;    # 国内服务器
}

upstream us_backend {
    server 10.0.2.10:3000;    # 美国服务器
}

upstream eu_backend {
    server 10.0.3.10:3000;    # 欧洲服务器
}

server {
    location / {
        proxy_pass http://$backend_pool;
    }
}

🔴 高级 / Advanced — 高级负载均衡策略

upstream 长连接池

upstream backend {
    server 192.168.1.10:3000;
    server 192.168.1.11:3000;

    # 到后端的长连接池
    keepalive 32;                # 每个 Worker 保持 32 个空闲长连接
    keepalive_requests 1000;     # 每个连接最多处理 1000 个请求
    keepalive_time 1h;           # 连接最长存活时间
    keepalive_timeout 60s;       # 空闲超时
}

server {
    location / {
        proxy_pass http://backend;
        proxy_http_version 1.1;              # 必须:keepalive 需要 HTTP/1.1
        proxy_set_header Connection "";       # 必须:清除 close 头
    }
}
无 keepalive:
每次请求: 建立 TCP 连接 → 发送请求 → 接收响应 → 关闭连接
          ↑ 三次握手 + 四次挥手,每个请求都重复

有 keepalive:
首次请求: 建立 TCP 连接 → 发送请求 → 接收响应 → 保持连接
后续请求: 直接复用连接 → 发送请求 → 接收响应 → 保持连接
          ↑ 省去 TCP 握手,减少延迟和 CPU 开销

自定义负载均衡(Lua)

# 使用 OpenResty 的 balancer_by_lua

upstream backend {
    server 192.168.1.10:3000;
    server 192.168.1.11:3000;

    balancer_by_lua_block {
        local balancer = require "ngx.balancer"

        -- 自定义选择逻辑
        local servers = {
            { host = "192.168.1.10", port = 3000, weight = 5 },
            { host = "192.168.1.11", port = 3000, weight = 3 },
        }

        -- 根据请求头选择后端
        local api_version = ngx.req.get_headers()["X-API-Version"]
        local target
        if api_version == "v2" then
            target = servers[2]
        else
            target = servers[1]
        end

        local ok, err = balancer.set_current_peer(target.host, target.port)
        if not ok then
            ngx.log(ngx.ERR, "balancer failed: ", err)
        end
    }
}

A/B 测试分流

# 使用 split_clients 实现百分比分流
split_clients $request_uri $variant {
    20%    v2_backend;     # 20% 的流量到 v2
    *      v1_backend;     # 80% 到 v1
}

upstream v1_backend {
    server 192.168.1.10:3000;
}

upstream v2_backend {
    server 192.168.1.11:3000;
}

server {
    location / {
        proxy_pass http://$variant;
        add_header X-Variant $variant;   # 方便调试
    }
}

灰度发布

# 基于 Cookie 的灰度发布
map $cookie_gray $backend {
    default   stable_backend;
    "true"    canary_backend;
}

# 基于 Header 的灰度
map $http_x_gray $backend {
    default   stable_backend;
    "true"    canary_backend;
}

# 基于 IP 的灰度(特定 IP 段走新版)
geo $is_gray {
    default        0;
    10.0.0.0/8     1;     # 内网用户走灰度
    203.0.113.0/24 1;     # 特定 IP 段
}

map $is_gray $backend {
    0    stable_backend;
    1    canary_backend;
}

upstream stable_backend {
    server 192.168.1.10:3000;
}

upstream canary_backend {
    server 192.168.1.20:3000;
}

server {
    location / {
        proxy_pass http://$backend;
        add_header X-Backend $backend;
    }
}

多层负载均衡架构

                Internet
                   │
            ┌──────┴──────┐
            │  L4 LB      │  ← LVS / HAProxy(四层,TCP 分流)
            │  (TCP)       │     处理海量连接,不做 HTTP 解析
            └──────┬──────┘
                   │
        ┌──────────┼──────────┐
        │          │          │
   ┌────┴────┐ ┌──┴──────┐ ┌─┴─────────┐
   │ Nginx 1 │ │ Nginx 2 │ │ Nginx 3   │  ← L7 LB(七层,HTTP 处理)
   │ (HTTP)  │ │ (HTTP)  │ │ (HTTP)    │     SSL 终止、路由、缓存
   └────┬────┘ └────┬────┘ └─────┬─────┘
        │           │            │
   ┌────┴────┐ ┌────┴────┐ ┌────┴────┐
   │ App 1   │ │ App 2   │ │ App 3   │  ← 后端应用
   └─────────┘ └─────────┘ └─────────┘
# Nginx 作为四层(TCP)负载均衡器
stream {
    upstream mysql_backend {
        hash $remote_addr consistent;
        server 10.0.1.10:3306;
        server 10.0.1.11:3306;
    }

    upstream redis_backend {
        server 10.0.2.10:6379;
        server 10.0.2.11:6379 backup;
    }

    server {
        listen 3306;
        proxy_pass mysql_backend;
        proxy_connect_timeout 5s;
    }

    server {
        listen 6379;
        proxy_pass redis_backend;
    }
}

小结 / Summary

层级你需要知道的 / What You Need to Know
🟢 基础upstream,轮询、加权、IP Hash、最少连接
🟡 进阶健康检查,会话保持,一致性哈希,地理位置分流
🔴 高级keepalive 连接池,A/B 测试,灰度发布,四层 TCP 负载均衡

下一章:HTTPS 与 TLS / HTTPS & TLS