反向代理与负载均衡
正向代理与反向代理
| 类型 | 代表的一方 | 客户端是否明确知道最终目标 | 常见用途 |
|---|---|---|---|
| Forward Proxy | Client | 通常知道 | 出口代理、访问控制 |
| Reverse Proxy | Server | 通常只访问代理地址 | 入口路由、TLS Termination、Load Balancing |
Nginx HTTP Module 的典型用途是 Reverse Proxy。它并不是开箱即用的通用 HTTPS Forward Proxy。
最小反向代理
nginx
location /api/ {
proxy_pass http://backend;
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 3s;
proxy_read_timeout 30s;
proxy_send_timeout 30s;
}Application 只有在请求来自可信 Proxy 时才能信任 Forwarded、X-Forwarded-For 等 Header。边界 Proxy 应覆盖外部伪造值,应用应配置可信 Proxy 范围。
Upstream
nginx
upstream backend {
least_conn;
server app-1.example.net:8080 weight=2 max_fails=2 fail_timeout=10s;
server app-2.example.net:8080 max_fails=2 fail_timeout=10s;
keepalive 32;
}
server {
location /api/ {
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_pass http://backend;
}
}| 方法 | 选择方式 | 适用边界 |
|---|---|---|
| Round Robin | 默认轮询,Weight 可影响比例 | 请求成本接近 |
least_conn | Active Connection 较少者优先 | 请求耗时差异较大 |
ip_hash | 根据 Client IP Hash | 粗粒度粘滞,受 NAT/Proxy 和地址变化影响 |
hash key consistent | 根据指定 Key 做 Consistent Hash | Cache Sharding 等场景 |
ip_hash 不是 Session Sharing。可靠方案是 Stateless Session、Shared Session Store 或业务 Token;粘滞路由只能降低跨实例概率,还会带来流量倾斜。
被动健康检查与重试
Open Source Nginx 常用 max_fails、fail_timeout 和 proxy_next_upstream 做被动失败判断。请求失败后是否换 Upstream 取决于错误类型、配置以及 Response 是否已发送给 Client。
自动重试非幂等请求可能重复创建订单或扣款。应限制重试条件和次数,并为业务操作设计 Idempotency Key。
WebSocket
nginx
map $http_upgrade $connection_upgrade {
default upgrade;
"" close;
}
location /ws/ {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_pass http://backend;
}WebSocket 的 Upgrade 和 Connection 是 Hop-by-hop Header,需要显式传给 Upstream。
uWSGI
旧 Django 笔记的 uWSGI 链路仍可理解,但 CentOS 7 安装命令不应照搬:
nginx
location / {
include uwsgi_params;
uwsgi_pass unix:/run/myapp/uwsgi.sock;
}uwsgi_pass 使用 uwsgi Protocol;若 Application Server 暴露 HTTP,则使用 proxy_pass,两者不可混用。