前言
Nginx 一半的生命在当"流量二传手":把请求转发给后端服务,并把多台后端"捏"成一个池子。这篇讲透反向代理与负载均衡的配置细节。
一、正向 vs 反向代理
正向代理(代理客户端): 反向代理(代理服务端):
客户端 → [代理] → 互联网 客户端 → [Nginx] → 后端集群
翻墙软件、公司出口 负载均衡、SSL卸载、缓存
服务器不知道真实客户端 客户端不知道真实后端
二、反向代理基础:proxy_pass
upstream app {
server 127.0.0.1:8080;
server 127.0.0.1:8081;
}
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://app;
# ---- 标准转发头(几乎必配)----
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# ---- 超时与缓冲 ----
proxy_connect_timeout 5s;
proxy_read_timeout 60s; # 后端慢接口调大
proxy_send_timeout 30s;
proxy_buffering on; # 响应先缓冲再发(默认)
}
}
proxy_pass 的斜杠陷阱:
# 带路径的 proxy_pass: /api/xxx -> 后端 /v1/xxx(替换 location 前缀)
location /api/ {
proxy_pass http://app/v1/;
}
# 不带路径(只有 host): 原样透传 /api/xxx
location /api/ {
proxy_pass http://app;
}
给后端传真实客户端 IP:后端拿到的 RemoteAddr 是 Nginx。后端应用需读 X-Real-IP 或解析 X-Forwarded-For(第一个 IP 是最初客户端)。
三、upstream 负载均衡策略
# 1. 轮询(默认) + 权重
upstream app {
server 10.0.1.11:8080 weight=3; # 扛 3/4 流量(机器好就多分)
server 10.0.1.12:8080 weight=1;
}
# 2. ip_hash: 同一客户端 IP 恒定打到同一后端(会话保持的土办法)
upstream app {
ip_hash;
server 10.0.1.11:8080;
server 10.0.1.12:8080;
}
# 3. least_conn: 转给当前连接数最少的(长短连接混合场景更公平)
upstream app {
least_conn;
server 10.0.1.11:8080;
server 10.0.1.12:8080;
}
server 参数(被动健康检查):
upstream app {
server 10.0.1.11:8080 max_fails=3 fail_timeout=30s;
# 30 秒内失败 3 次 → 标记不可用 30 秒
server 10.0.1.12:8080 backup; # 备胎: 全挂了才上
server 10.0.1.13:8080 down; # 手动摘除(维护模式)
}
开源版 Nginx 只有被动检查(靠真实流量发现失败);主动健康检查需要 Nginx Plus 或 tengine,或改用 keepalived+VIP / K8s Ingress 的方案。
四、典型场景配置
动静分离
server {
listen 80;
server_name example.com;
location /static/ { # 静态: 本地直出
root /var/www;
expires 30d;
}
location /api/ { # 动态: 转后端
proxy_pass http://app;
}
}
路径重写
# 老路径迁移
location /old/ {
rewrite ^/old/(.*)$ /new/$1 permanent; # 301
}
# 带正则的转发
location ~ ^/v(\d+)/ {
proxy_pass http://app; # 正则 location 里 proxy_pass 不能带 URI
proxy_set_header X-API-Version $1; # 捕获组传给后端
}
本地缓存(给慢后端减负)
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=api_cache:10m max_size=1g inactive=10m;
server {
location /api/public/ {
proxy_pass http://app;
proxy_cache api_cache;
proxy_cache_valid 200 5m; # 200 响应缓存 5 分钟
proxy_cache_key $uri$is_args$args;
add_header X-Cache-Status $upstream_cache_status; # HIT/MISS 调试头
}
}
四层代理(TCP/UDP,转发 MySQL/Redis)
# nginx.conf 顶层(与 http 块平级)
stream {
upstream mysql {
server 10.0.2.21:3306;
}
server {
listen 3306;
proxy_pass mysql;
}
}
WebSocket
location /ws/ {
proxy_pass http://app;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade; # 协议升级头
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600s; # 长连接别太早掐
}
五、验证与排障
nginx -t && systemctl reload nginx
# 看负载均衡实际效果
for i in $(seq 10); do curl -s http://api.example.com/backend-id; done
# 轮询应轮流出现不同后端标识
# 关键日志变量(加进 log_format 排障神器)
log_format upstream '$remote_addr -> $upstream_addr '
'status=$status ups=$upstream_status rt=$upstream_response_time';
# 10.0.0.5 -> 10.0.1.11:8080 status=200 ups=200 rt=0.012
# 常见错误码
# 502: 后端连接失败(进程挂/端口错/防火墙)
# 504: 后端超时(proxy_read_timeout 调大或优化后端)
# 499: 客户端等不及主动断开(后端太慢)
502 排查链路:curl 后端端口 → ss -tlnp 看监听 → /var/log/nginx/error.log 看具体 connect 错误。
六、架构位置示意
用户 ─► DNS/CDN ─► [LB/VIP] ─► Nginx 集群(七层: TLS/路由/缓存)
│
├─► 静态文件(本地/对象存储)
├─► App 集群(upstream 轮询)
└─► 内部服务(stream 四层转发)
小结
| 需求 | 配置 |
|---|---|
| 转发 | proxy_pass + 四个 proxy_set_header |
| 负载策略 | weight / ip_hash / least_conn |
| 健康检查 | max_fails + fail_timeout(被动) |
| 会话保持 | ip_hash(或应用层 token) |
| 真实 IP | X-Real-IP / X-Forwarded-For |
| 排障 | $upstream_addr/$upstream_response_time 写进日志 |
本文是「Linux 运维」系列第 9 篇。