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 负载均衡 |