很多运维工程师对反向代理的理解停留在“配置一下 proxy_pass”的层面,但对底层原理、负载均衡算法、会话保持机制等核心概念一知半解。这篇文章将从网络协议层面讲清反向代理的本质,详细介绍 Nginx 反向代理的配置、负载均衡策略、缓存机制、高可用方案,帮助你从“会用”提升到“精通”。
前置知识:HTTP 协议基础、TCP/IP 基础
实验环境:CentOS Stream 9 / Ubuntu 24.04 LTS,Nginx 1.26+
1 反向代理的本质
1.1 正向代理 vs 反向代理
正向代理(Forward Proxy):
客户端 代理服务器 目标服务器
| | |
用户配置代理 | ───── GET / ────> | |
请求发送到代理 | | ───── GET / ────────> |
| | |
代理转发请求 | | <──── 200 OK ─────── |
| | |
返回结果给用户 | <──── 200 OK ──── | |
| | |
用途:翻墙、缓存、匿名访问
反向代理(Reverse Proxy):
客户端 代理服务器 目标服务器
| | |
用户不知道真实服务器 | ───── GET / ────> | |
请求发到代理 | | ───── GET / ────────> |
| | <──── 200 OK ─────── |
代理转发给后端 | | |
| <──── 200 OK ──── | |
返回结果给用户 | | |
| | |
用途:负载均衡、安全防护、缓存加速
1.2 反向代理的工作原理
┌─────────────────────────────────────────────────────┐
│ Nginx 反向代理 │
│ │
│ 接收请求 │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ 协议解析 │ 解析 HTTP 请求头、正文 │
│ └──────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ 连接池管理 │ 管理与后端服务器的连接 │
│ └──────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ 负载均衡 │ 选择合适的后端服务器 │
│ └──────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
客户端 ────────> │ │ 请求转发 │ 转发请求到后端 │
│ └──────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ 响应处理 │ 接收后端响应,处理头信息 │
│ └──────────────┘ │
│ │ │
│ ▼ │
客户端 <──────── │ ┌──────────────┐ │
│ │ 缓存处理 │ 如果配置了缓存 │
│ └──────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ 日志记录 │ 记录访问日志 │
│ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────┘
1.3 反向代理的优势
# 反向代理核心优势示例
upstream backend {
server 127.0.0.1:8080;
server 127.0.0.1:8081;
}
server {
listen 80;
server_name example.com;
# 优势 1: 隐藏真实后端
# 客户端只能看到 Nginx,不知道后端有几台服务器
location / {
proxy_pass http://backend;
}
# 优势 2: 负载均衡
# 自动分发请求到不同后端
# 配合 upstream 实现
# 优势 3: SSL 终结
# 后端无需配置 SSL,Nginx 统一处理
# 节省后端资源
# 优势 4: 缓存加速
# 静态资源缓存,减少后端压力
# 优势 5: 安全防护
# 过滤恶意请求,防护 DDoS
# 优势 6: 灰度发布
# 按比例分流到不同版本
}
2 基础反向代理配置
2.1 最简反向代理
server {
listen 80;
server_name example.com;
# 代理到后端
location / {
proxy_pass http://127.0.0.1:8080;
}
}
2.2 完整代理配置
server {
listen 80;
server_name example.com;
location / {
# 后端地址
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_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
# HTTP 版本
proxy_http_version 1.1;
# 连接管理
proxy_set_header Connection "";
# 超时配置
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# 缓冲配置
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
proxy_busy_buffers_size 8k;
# 错误处理
proxy_intercept_errors on;
proxy_next_upstream error timeout http_502 http_503 http_504;
}
}
2.3 代理头信息详解
# 常用代理头说明
# Host: 请求的主机名
# 客户端: GET / HTTP/1.1
# Host: example.com
# Nginx: GET / HTTP/1.1
# Host: example.com
# X-Real-IP: 客户端真实 IP
# 客户端 IP: 203.0.113.10
# Nginx 添加: X-Real-IP: 203.0.113.10
# X-Forwarded-For: 经过的代理链
# X-Forwarded-For: 203.0.113.10, 10.0.0.1, 192.168.1.1
# 客户端IP 第一层代理 第二层代理
# X-Forwarded-Proto: 原始协议
# X-Forwarded-Proto: https
# 测试代理头
curl -v http://example.com 2>&1 | grep -E "^> (Host|X-Real-IP|X-Forwarded)"
2.4 日志配置
# 记录代理相关信息
log_format proxy_log '$remote_addr - $remote_user [$time_local] '
'"$request" '
'$status $body_bytes_sent '
'"$http_referer" '
'"$http_user_agent" '
'rt=$request_time '
'uct="$upstream_connect_time" '
'uht="$upstream_header_time" '
'urt="$upstream_response_time" '
'u="$upstream_addr"';
access_log /var/log/nginx/proxy.log proxy_log;
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend;
# 只记录错误日志
access_log off;
}
location /api/ {
proxy_pass http://api_backend;
# 详细记录 API 请求
access_log /var/log/nginx/api.log proxy_log;
}
}
3 负载均衡策略
3.1 轮询(Round Robin)
# 默认策略,按顺序逐个分配
upstream backend {
server 127.0.0.1:8080;
server 127.0.0.1:8081;
server 127.0.0.1:8082;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend;
}
}
# 请求分配序列:
# 请求1 -> 127.0.0.1:8080
# 请求2 -> 127.0.0.1:8081
# 请求3 -> 127.0.0.1:8082
# 请求4 -> 127.0.0.1:8080
# ...循环
3.2 加权轮询(Weighted Round Robin)
# weight 越大,被选中的概率越高
upstream backend {
server 127.0.0.1:8080 weight=5;
server 127.0.0.1:8081 weight=2;
server 127.0.0.1:8082 weight=1;
}
# 请求分配比例:
# 8080: 5/(5+2+1) = 62.5%
# 8081: 2/(5+2+1) = 25%
# 8082: 1/(5+2+1) = 12.5%
3.3 IP 哈希(IP Hash)
# 同一 IP 的请求始终发送到同一后端
upstream backend {
ip_hash;
server 127.0.0.1:8080;
server 127.0.0.1:8081;
server 127.0.0.1:8082;
}
# 场景:需要会话保持时使用
# 注意:后端服务器变更时,可能导致会话丢失
3.4 最少连接(Least Connections)
# 将请求发送到当前连接数最少的服务器
upstream backend {
least_conn;
server 127.0.0.1:8080;
server 127.0.0.1:8081;
server 127.0.0.1:8082;
}
# 场景:请求处理时间差异较大时使用
3.5 Hash 哈希(Generic Hash)
# 根据任意 key 分配请求
upstream backend {
hash $request_uri consistent;
server 127.0.0.1:8080;
server 127.0.0.1:8081;
}
# consistent: 开启一致性哈希,减少服务器变更时的数据迁移
# $request_uri: 根据请求 URI 分配
# 也可以用 $cookie_jsessionid 等
3.6 随机(Random)
# 随机选择两台服务器,然后选择其中一台
upstream backend {
random two [method=round_robin];
server 127.0.0.1:8080;
server 127.0.0.1:8081;
server 127.0.0.1:8082;
server 127.0.0.1:8083;
}
# method:
# round_robin: 默认,选择连接数最少的
# iqm: 至少 2 个请求后比较
# fair: 连接数最少的(需要第三方模块)
3.7 负载均衡算法对比
| 算法 |
特点 |
适用场景 |
| round_robin |
默认,均匀分配 |
后端性能一致 |
| weighted |
按权重分配 |
后端性能不一致 |
| ip_hash |
会话保持 |
有状态服务 |
| least_conn |
负载感知 |
长连接服务 |
| hash |
自定义 key |
缓存命中 |
| random |
随机选择 |
无状态服务 |
4 健康检查配置
4.1 被动健康检查
# 被动检查:只检查失败的请求
upstream backend {
server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
server 127.0.0.1:8081 max_fails=3 fail_timeout=30s;
# max_fails: 失败次数达到此值认为服务器不可用
# fail_timeout: 服务器不可用持续时间
}
# 参数说明:
# max_fails=3: 30 秒内连续 3 次失败,标记为不可用
# fail_timeout=30s: 30 秒后重新尝试
4.2 主动健康检查(第三方模块)
# 需要 nginx-upstream-check-module
upstream backend {
zone backend 64k;
# 添加健康检查
check interval=3000 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;
server 127.0.0.1:8080;
server 127.0.0.1:8081;
}
# interval: 检查间隔(毫秒)
# rise: 连续成功次数,恢复为可用
# fall: 连续失败次数,标记为不可用
# timeout: 检查超时(毫秒)
# type: 检查类型(tcp|http|ssl_hello|mysql|ajp)
4.3 健康检查端点
# 后端应用提供健康检查端点
server {
listen 8080;
server_name _;
# 健康检查
location /health {
access_log off;
return 200 "OK\n";
add_header Content-Type text/plain;
}
# 就绪检查(检查依赖服务)
location /ready {
access_log off;
# 检查数据库连接
# 如果依赖不可用,返回 503
set $ready 1;
if ($database_connected = 0) {
set $ready 0;
}
if ($ready = 0) {
return 503;
}
return 200 "Ready\n";
}
# 应用主路由
location / {
# 应用代码
}
}
5 会话保持机制
5.1 Session 与 Cookie
HTTP 无状态协议的问题:
1. 用户登录后,下一个请求无法识别用户身份
2. 购物车、用户信息等无法跨请求保持
解决方案:
1. Session + Cookie
2. Token(JWT等)
3. URL 参数
会话保持的挑战:
- 多台后端服务器
- 如何让同一用户的请求打到同一台服务器
5.2 Nginx 会话保持方案
# 方案 1: ip_hash(简单但有限制)
upstream backend {
ip_hash;
server 127.0.0.1:8080;
server 127.0.0.1:8081;
}
# 方案 2: Cookie 标记
upstream backend {
server 127.0.0.1:8080;
server 127.0.0.1:8081;
# 如果后端服务器会添加 cookie
# 可以使用 $cookie_name 来做 hash
}
# 方案 3: URI 参数标记
upstream backend {
hash $cookie_jsessionid;
server 127.0.0.1:8080;
server 127.0.0.1:8081;
}
# 方案 4: 基于后端的会话保持响应
# 后端在首次响应时设置 cookie
# Nginx 通过 cookie 识别用户
upstream backend {
hash $cookie_PHPSESSID consistent;
server 127.0.0.1:8080;
server 127.0.0.1:8081;
}
5.3 分布式会话问题
# 问题:Nginx ip_hash 不够精确
# 原因:NAT 环境下,多个用户共享同一出口 IP
# 解决方案 1: 后端标记
# 应用在 cookie 中存储 session_id
# 后端共享 session 到 Redis/Memcached
# 解决方案 2: JWT 无状态会话
# 不需要后端存储 session
# session 信息加密在 token 中
# 解决方案 3: Sticky Session(应用层)
upstream backend {
# 使用 sticky cookie
sticky cookie srv_id expires=1h domain=.example.com path=/;
server 127.0.0.1:8080;
server 127.0.0.1:8081;
}
5.4 Session 共享配置
# Redis Session 共享示例(PHP)
# /etc/php.ini 或 .user.ini
session.save_handler = redis
session.save_path = "tcp://127.0.0.1:6379?database=0"
# 或者在代码中
<?php
ini_set('session.save_handler', 'redis');
ini_set('session.save_path', 'tcp://127.0.0.1:6379?database=0');
?>
# Java Spring Session
# application.yml
# spring:
# data:
# redis:
# host: localhost
# port: 6379
6 代理缓存配置
6.1 缓存机制原理
代理缓存工作流程:
客户端请求 -> Nginx 缓存检查
│
├── 命中(HIT)
│ └── 直接返回缓存
│
└── 未命中(MISS)
│
└── 转发给后端
│
├── 后端返回
│ └── 存储到缓存
│ └── 返回给客户端
│
└── 缓存命中时直接返回
6.2 缓存配置
# 定义缓存目录和大小
proxy_cache_path /var/cache/nginx levels=1:2
keys_zone=api_cache:100m
max_size=10g
inactive=60m
use_temp_path=off;
# 定义缓存 Key
proxy_cache_key "$scheme$request_method$host$request_uri";
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend;
# 启用缓存
proxy_cache api_cache;
# 缓存有效期
proxy_cache_valid 200 60m; # 200 响应缓存 60 分钟
proxy_cache_valid 404 10m; # 404 响应缓存 10 分钟
proxy_cache_valid any 5m; # 其他响应缓存 5 分钟
# 缓存控制头
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_background_update on;
proxy_cache_lock on;
# 绕过缓存的条件
proxy_cache_bypass $cookie_nocache $arg_nocache;
proxy_no_cache $cookie_nocache $arg_nocache;
# 添加缓存状态头
add_header X-Cache-Status $upstream_cache_status;
}
}
# $upstream_cache_status 值:
# MISS: 未命中,请求被传递到后端
# HIT: 命中,返回缓存内容
# EXPIRED: 缓存过期,验证后返回
# STALE: 返回过期缓存(后端不可用)
# UPDATING: 缓存过期,正在更新
# REVALIDATED: 缓存验证通过
6.3 缓存清理
# 缓存清理配置(需要 ngx_cache_purge 模块)
proxy_cache_path /var/cache/nginx levels=1:2
keys_zone=api_cache:100m
max_size=10g
inactive=60m;
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend;
proxy_cache api_cache;
}
# 缓存清理接口
location ~ /purge(/.*) {
proxy_cache_purge api_cache "$scheme$request_method$host$1";
# 仅允许特定 IP
allow 127.0.0.1;
allow 10.0.0.0/8;
deny all;
}
}
# 清理缓存示例
# curl -X PURGE http://example.com/api/data
6.4 全面缓存配置示例
proxy_cache_path /var/cache/nginx/api levels=1:2:3
keys_zone=api_cache:100m
max_size=10g
inactive=7d
use_temp_path=off;
proxy_cache_path /var/cache/nginx/static levels=1:2
keys_zone=static_cache:50m
max_size=5g
inactive=30d;
server {
listen 80;
server_name example.com;
# API 缓存
location /api/ {
proxy_pass http://api_backend;
proxy_cache api_cache;
proxy_cache_valid 200 5m;
proxy_cache_valid 404 1m;
proxy_cache_use_stale error timeout updating;
proxy_cache_lock on;
add_header X-Cache-Status $upstream_cache_status;
# 不缓存 POST PUT DELETE
proxy_cache_methods GET HEAD POST;
proxy_cache_bypass $cookie_nocache $arg_nocache $arg_cache;
proxy_no_cache $cookie_nocache $arg_nocache $request_method;
}
# 静态资源缓存
location /static/ {
proxy_pass http://static_backend;
proxy_cache static_cache;
proxy_cache_valid 200 30d;
proxy_cache_valid 404 1m;
expires 30d;
add_header Cache-Control "public, no-transform";
}
# 绕过缓存
location /api/private/ {
proxy_pass http://api_backend;
proxy_cache_bypass 1; # 永远不缓存
proxy_no_cache 1;
}
}
7 高可用方案
构建高可用的代理层是保障服务稳定性的关键。以下介绍几种常见的方案。
7.1 Keepalived + Nginx
通过 Keepalived 实现虚拟 IP(VIP)的漂移,当主节点故障时,备用节点接管 VIP。
# 服务器 A 配置(主)
# /etc/keepalived/keepalived.conf
vrrp_script chk_nginx {
script "/usr/local/bin/check_nginx.sh"
interval 2
weight -20
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1234
}
virtual_ipaddress {
192.168.1.100
}
track_script {
chk_nginx
}
}
# 服务器 B 配置(备)
# /etc/keepalived/keepalived.conf
vrrp_script chk_nginx {
script "/usr/local/bin/check_nginx.sh"
interval 2
weight -20
}
vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 51
priority 90
advert_int 1
authentication {
auth_type PASS
auth_pass 1234
}
virtual_ipaddress {
192.168.1.100
}
track_script {
chk_nginx
}
}
#!/bin/bash
# /usr/local/bin/check_nginx.sh
nginx_status=$(curl -s -o /dev/null -w "%{http_code}" http://localhost/health)
if [ $nginx_status -ne 200 ]; then
systemctl restart nginx
sleep 2
nginx_status=$(curl -s -o /dev/null -w "%{http_code}" http://localhost/health)
if [ $nginx_status -ne 200 ]; then
exit 1
fi
fi
exit 0
7.2 DNS 轮询高可用
# DNS A 记录配置多个 IP
# example.com A 192.168.1.101
# example.com A 192.168.1.102
# example.com A 192.168.1.103
# 优点:简单
# 缺点:DNS 缓存问题,故障切换慢
# 建议配合健康检查
7.3 Consul + Nginx
结合 Consul 的服务发现能力,可以动态地更新 Nginx 的 upstream 配置,实现更灵活的 高可用集群管理。
# Consul Template 动态更新 upstream
# /etc/nginx/conf.d/upstream.ctmpl
upstream backend {
{{ range service "api" }}
server {{ .Address }}:{{ .Port }};
{{ end }}
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend;
}
}
#!/bin/bash
# consul-template 配置
# consul-template -config /etc/consul-template/nginx.hcl
# /etc/consul-template/nginx.hcl
# template {
# source = "/etc/nginx/conf.d/upstream.ctmpl"
# destination = "/etc/nginx/conf.d/upstream.conf"
# command = "nginx -s reload"
# }
# consul 服务注册
# {
# "services": [
# {
# "name": "api",
# "address": "127.0.0.1",
# "port": 8080,
# "check": {
# "http": "http://127.0.0.1:8080/health",
# "interval": "10s"
# }
# }
# ]
# }
8 实际应用场景
8.1 API 网关场景
# API 网关完整配置
upstream user_service {
server 127.0.0.1:8001;
server 127.0.0.1:8002;
}
upstream order_service {
server 127.0.0.1:8003;
server 127.0.0.1:8004;
}
upstream payment_service {
server 127.0.0.1:8005;
}
proxy_cache_path /var/cache/nginx levels=1:2
keys_zone=api_cache:100m
max_size=10g
inactive=5m;
server {
listen 80;
server_name api.example.com;
# 用户服务
location /api/users {
proxy_pass http://user_service;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# 限流
limit_req zone=api burst=50 nodelay;
}
# 订单服务
location /api/orders {
proxy_pass http://order_service;
proxy_set_header Host $host;
# 限流
limit_req zone=api burst=30 nodelay;
# 缓存(只读)
proxy_cache api_cache;
proxy_cache_valid 200 1m;
proxy_cache_bypass $cookie_nocache;
}
# 支付服务(高安全)
location /api/payment {
proxy_pass http://payment_service;
# 严格限流
limit_req zone=payment burst=5 nodelay;
# 不缓存
proxy_cache_bypass 1;
proxy_no_cache 1;
}
# 默认
location / {
return 404;
}
}
8.2 单页应用(SPA)场景
# Vue/React 单页应用配置
server {
listen 80;
server_name app.example.com;
root /var/www/spa/dist;
index index.html;
# 缓存静态资源
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
# HTML 不缓存
location = /index.html {
expires -1;
add_header Cache-Control "no-store, no-cache, must-revalidate";
}
# React Router 处理:所有路由都返回 index.html
location / {
try_files $uri $uri/ /index.html;
}
# API 代理
location /api/ {
proxy_pass http://api_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
8.3 WebSocket 代理
# WebSocket 代理配置
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream websocket_backend {
server 127.0.0.1:8080;
server 127.0.0.1:8081;
}
server {
listen 80;
server_name ws.example.com;
location /ws {
proxy_pass http://websocket_backend;
# WebSocket 必需配置
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
# 超时配置(WebSocket 可能长时间连接)
proxy_connect_timeout 7d;
proxy_send_timeout 7d;
proxy_read_timeout 7d;
# 缓冲关闭
proxy_buffering off;
}
}
8.4 gRPC 代理
# gRPC 代理配置
upstream grpc_backend {
server 127.0.0.1:50051;
server 127.0.0.1:50052;
}
server {
listen 443 ssl http2;
server_name grpc.example.com;
ssl_certificate /etc/nginx/ssl/grpc.crt;
ssl_certificate_key /etc/nginx/ssl/grpc.key;
ssl_protocols TLSv1.2 TLSv1.3;
location / {
# gRPC 传输
grpc_pass grpc://grpc_backend;
# 错误处理
error_page 502 = /error502grpc;
}
location = /error502grpc {
internal;
default_type application/grpc;
add_header grpc-status 14;
add_header content-type application/grpc;
add_header grpc-message "unavailable";
return 204;
}
}
9 性能优化
9.1 连接池配置
# upstream 连接池
upstream backend {
server 127.0.0.1:8080;
server 127.0.0.1:8081;
# HTTP/1.1 连接池
keepalive 32;
keepalive_requests 1000;
keepalive_timeout 60s;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend;
# 启用 HTTP/1.1
proxy_http_version 1.1;
# 清空 Connection 头
proxy_set_header Connection "";
}
}
9.2 缓冲区优化
# 代理缓冲区
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
proxy_busy_buffers_size 16k;
# 大型响应优化
proxy_max_temp_file_size 1024m;
proxy_temp_file_write_size 8k;
# FastCGI 缓冲区(PHP)
fastcgi_buffering on;
fastcgi_buffer_size 4k;
fastcgi_buffers 8 4k;
fastcgi_busy_buffers_size 8k;
9.3 零拷贝
# 启用零拷贝传输
sendfile on;
tcp_nopush on;
tcp_nodelay on;
# AIO 异步 I/O(适合大文件)
aio on;
directio 4m;
output_buffers 1 128k;
9.4 Gzip 压缩
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml application/json application/javascript
application/xml application/xml+rss application/javascript
image/svg+xml;
gzip_disable "msie6";
10 监控与故障排查
良好的监控和快速的故障排查是 运维 & 测试 工作的核心。
10.1 监控指标
#!/bin/bash
# monitor_upstream.sh - 监控 upstream 健康状态
echo "=== Upstream 健康状态 ==="
# 查看 upstream 连接状态
curl -s http://localhost/status
# 需要启用 nginx-module-vts
# 检查 upstream 响应时间
echo ""
echo "=== 响应时间测试 ==="
time curl -s -o /dev/null http://localhost/health
# 检查各 upstream
echo ""
echo "=== Upstream 可用性 ==="
for port in 8080 8081 8082; do
if timeout 1 bash -c "echo > /dev/tcp/127.0.0.1/$port" 2>/dev/null; then
echo "✓ 127.0.0.1:$port 可用"
else
echo "✗ 127.0.0.1:$port 不可用"
fi
done
# 查看错误日志
echo ""
echo "=== 最近代理错误 ==="
tail -20 /var/log/nginx/error.log | grep -E "upstream|proxy" || echo "无错误"
10.2 常见故障排查
# 1. 502 Bad Gateway
# 检查后端是否运行
ss -tlnp | grep :8080
# 检查连接
curl -v http://127.0.0.1:8080
# 查看错误日志
tail -50 /var/log/nginx/error.log | grep upstream
# 2. 504 Gateway Timeout
# 检查后端处理时间
# 查看 nginx 日志中的 uht/urt 字段
# 3. 503 Service Unavailable
# 检查限流配置
# 检查后端是否过载
# 4. 负载不均
# 查看 access_log 中 $upstream_addr
awk '{print $NF}' /var/log/nginx/access.log | sort | uniq -c | sort -rn
10.3 调试配置
# 调试代理
server {
listen 80;
server_name debug.example.com;
location / {
# 开启详细日志
rewrite ^(.*)$ /debug$1 break;
}
location /debug/ {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# 调试头
add_header X-Upstream-Addr $upstream_addr;
add_header X-Upstream-Status $upstream_status;
add_header X-Upstream-Response-Time $upstream_response_time;
}
}
11 总结与速查
11.1 核心配置速查
# 反向代理基础配置
location / {
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_http_version 1.1;
proxy_set_header Connection "";
}
# 负载均衡
upstream backend {
server 127.0.0.1:8080;
server 127.0.0.1:8081 weight=2;
ip_hash;
least_conn;
}
# 健康检查
upstream backend {
server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
server 127.0.0.1:8081 max_fails=3 fail_timeout=30s;
}
# 缓存
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=api_cache:100m;
location / {
proxy_cache api_cache;
proxy_cache_valid 200 60m;
}
# WebSocket
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
11.2 场景配置速查
| 场景 |
关键配置 |
| API 网关 |
多 upstream、限流、缓存 |
| SPA |
try_files、静态资源缓存 |
| WebSocket |
Upgrade 头、长超时 |
| gRPC |
HTTP/2、grpc_pass |
| 高可用 |
Keepalived、DNS 轮询 |
11.3 排查命令速查
# 查看 upstream 状态
curl http://localhost/status
# 查看错误日志
tail -100 /var/log/nginx/error.log | grep upstream
# 测试后端
curl -v http://127.0.0.1:8080/health
# 查看连接数
ss -ant | grep :8080
# 查看负载分布
awk '{print $NF}' /var/log/nginx/access.log | sort | uniq -c | sort -rn
11.4 性能优化要点
1. 连接池:keepalive 32-64
2. 缓冲区:proxy_buffering on
3. 零拷贝:sendfile on + tcp_nopush
4. 压缩:gzip on
5. HTTP/2:listen 443 ssl http2
6. 缓存:proxy_cache 减少后端压力