6.1 核心概念
- 负载均衡(Load Balancing)
- 把大量请求按某种规则分摊到多台后端服务器,避免单机过载,同时实现横向扩容与容错。
- 轮询(Round Robin)
- Nginx 默认策略,请求依次分给每台后端,循环往复。简单公平,适合后端配置一致的场景。
- 加权轮询(Weighted RR)
- 给每台后端设
weight,权重越高分到的请求越多。用于后端配置不均(如新机器更强)时按能力分配。 - ip_hash
- 按客户端 IP 做哈希,同一 IP 总落到同一后端。用于需要"会话粘性"的场景(如本地 session)。
- least_conn
- 把请求发给当前活跃连接数最少的后端。适合请求处理时长差异大的场景,比轮询更能防止某台堆积。
- 被动健康检查(max_fails / fail_timeout)
- Nginx 开源版靠转发失败次数判断后端是否"不可用",达到阈值就在一段时间内不再向它派发请求。
6.2 默认轮询与加权
upstream backend {
server 10.0.0.11:8080;
server 10.0.0.12:8080;
server 10.0.0.13:8080;
}
# 加权:性能强的机器多分流量
upstream weighted {
server 10.0.0.11:8080 weight=5; # 5/8 的请求
server 10.0.0.12:8080 weight=2;
server 10.0.0.13:8080 weight=1;
}
6.3 ip_hash 与 least_conn
# 同一客户端 IP 固定落一台(会话粘性)
upstream sticky {
ip_hash;
server 10.0.0.11:8080;
server 10.0.0.12:8080;
}
# 发给连接数最少的后端(长请求友好)
upstream leastconn {
least_conn;
server 10.0.0.11:8080;
server 10.0.0.12:8080;
}
ip_hash 不是理想的会话保持
大量用户共用一个出口 NAT IP(如整个公司/校园)时,ip_hash 会把他们全压到同一台。更干净的做法是让 session 无状态(存 Redis / JWT),后端就能随意轮询。会话保持是"没办法时的办法",不是首选架构。
6.4 健康检查与失败剔除
upstream backend {
# 20 秒内失败 3 次,则标记该后端 down 20 秒
server 10.0.0.11:8080 max_fails=3 fail_timeout=20s;
server 10.0.0.12:8080 max_fails=3 fail_timeout=20s;
# 备用机:只有主力全挂了才启用
server 10.0.0.99:8080 backup;
# 临时下线一台(发布时)
server 10.0.0.13:8080 down;
}
- backup
- 标记为备用后端,仅当所有非 backup 后端都不可用时才接收流量。用作冗余兜底。
- down
- 手动标记该后端永久下线,Nginx 不再向它转发。发布/维护单台时临时加上。
主动健康检查在商业版
开源 Nginx 只有被动健康检查(靠真实请求失败来发现问题)。主动健康检查(定期主动探测 /healthz)是 Nginx Plus 商业特性,或用 nginx_upstream_check_module 第三方模块。K8s 场景则由 Ingress + readiness probe 承担。
6.5 失败重试
location / {
proxy_pass http://backend;
# 遇到这些情况时,换一台后端重试
proxy_next_upstream error timeout http_502 http_503 http_504;
proxy_next_upstream_tries 2; # 最多再试 2 台
proxy_next_upstream_timeout 10s; # 重试总耗时上限
}
非幂等请求慎重试
POST/PUT 这类可能产生副作用的请求,自动重试可能导致"下两次单"。默认 proxy_next_upstream 不会对非幂等请求重试(除非显式加 non_idempotent)。转账、下单等接口切勿盲目开启重试。
6.6 keepalive 长连接
upstream backend {
server 10.0.0.11:8080;
server 10.0.0.12:8080;
keepalive 64; # 每个 worker 与后端保持的空闲长连接数
}
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection ""; # 关键:清空 Connection 才能复用
}
没有 keepalive,Nginx 每次转发都要与后端重新三次握手、慢启动,高并发下这笔开销巨大。启用后连接被复用,延迟和 CPU 都明显下降——这是生产反代的必备优化。
6.7 一个完整均衡配置
upstream api_cluster {
least_conn;
server 10.0.0.11:8080 weight=2 max_fails=3 fail_timeout=15s;
server 10.0.0.12:8080 weight=2 max_fails=3 fail_timeout=15s;
server 10.0.0.13:8080 weight=1;
server 10.0.0.99:8080 backup;
keepalive 64;
}
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://api_cluster;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_next_upstream error timeout http_502 http_503;
}
}
6.8 小结与下一步
- 默认轮询;weight 加权、ip_hash 会话粘性、least_conn 连接最少优先。
- 被动健康检查靠 max_fails/fail_timeout 剔除坏后端;backup 兜底、down 手动下线。
- proxy_next_upstream 换机重试,但非幂等请求要谨慎。
- keepalive + HTTP/1.1 + 清空 Connection 复用后端连接,是必备优化。
- 无状态 session 优于 ip_hash 粘性。
- 下一章给站点穿上盔甲——HTTPS 与 TLS。