3.1 反向代理:把后端藏到流量背后


3.1 反向代理:把后端藏到流量背后

本节摘要:反向代理指 Nginx 代表后端服务器接收客户端请求并转发响应。核心是 proxy_pass 及其配套的头部改写、超时与故障页面配置——代理的第一原则是"忠实转达",常见故障几乎都源于转达失真。

最小可用代理

upstream app_backend { server 10.0.1.11:8080; } server { listen 80; server_name shop.example.com; location / { proxy_pass http://app_backend; } }

三行配置就能转发,但直接上线会立刻遇到两类问题:后端日志里客户端 IP 全是 Nginx 机器的 IP;后端应用收到的 Host 是 upstream 名字而不是域名。都是头部转达失真。

头部改写:让后端看见真相

location / { proxy_pass http://app_backend; proxy_set_header Host $host; # 保留原始域名 proxy_set_header X-Real-IP $remote_addr; # 直连客户端 IP proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 链路追加 proxy_set_header X-Forwarded-Proto $scheme; # 原始协议 }

X-Forwarded-For 是追加语义:多层代理时每层把自己的下游 IP 加到末尾,后端取第一个才是真实客户端。应用侧(如 Spring 的 ForwardedHeaderFilter、Express 的 trust proxy)要显式开启信任,否则头部照样没人读。

图:三级代理下的头部传递

图:三级代理下的头部传递

⚠️ X-Forwarded-For 可被客户端伪造首段,风控取 IP 时应使用直连层写入的 X-Real-IP 或可信代理链推导。

超时与故障页:代理的止损线

proxy_connect_timeout 3s; proxy_send_timeout 10s; proxy_read_timeout 30s; # 等后端响应的最长时间 proxy_intercept_errors on; # 后端错误码由本机页面接管 error_page 502 503 504 /50x.html; location = /50x.html { root /data/www/error; internal; }

proxy_read_timeout 必须大于后端最慢接口的耗时,否则慢接口会被掐断成 504;反过来又不能无限放宽,否则后端假死时连接堆积。30s 是多数业务的安全线,特殊慢接口单独在 location 覆盖。

代理路径的两个易错点

一是 proxy_pass 的转发目标带不带斜杠,决定 location 前缀是否从 URI 里剥掉:

location /api/ { proxy_pass http://app/; # /api/user → 后端收到 /user } location /api/ { proxy_pass http://app; # /api/user → 后端收到 /api/user }

二是 upstream 里写域名时,DNS 只在启动时解析一次,后端换 IP 不重启不生效;动态解析要用变量形式配合 resolver。

上游长连接:被默认值坑掉的吞吐

proxy_pass 默认每个请求向后端新建一条 TCP 连接,用完即关。高 QPS 下这表现为:后端机器上大量 TIME_WAIT 状态的连接、Nginx 出站端口被快速消耗、每请求多付一次建连往返。打开上游 keepalive 是代理上线的标准动作:

upstream app_backend { server 10.0.1.11:8080; keepalive 64; # 每 worker 的空闲连接池大小 keepalive_requests 1000; # 单连接复用上限 keepalive_timeout 60s; } server { location / { proxy_pass http://app_backend; proxy_http_version 1.1; # keepalive 必须 1.1 proxy_set_header Connection ""; # 清掉默认的 close 头 } }

三条缺一不可:不开 1.1、不清 Connection 头,连接池形同虚设。上线后验证同样简单,看后端机器的 TIME_WAIT 数量是否断崖式下降,Nginx 侧的出站端口消耗速率是否放缓。一次真实改造里,仅这一组配置让 P99 降了 15ms——省的全是建连往返。

与后端一起排一次 504

代理上线初期最常见的报障是 504。排查按两步走。第一步看错误日志关键词区分两类:upstream timed out 是等响应超时,connect() failed 是连不上。第二步分别处理。前者的典型成因是 proxy_read_timeout 短于后端最慢接口;后者的成因多半是后端监听地址写了回环而 Nginx 从另一网卡访问,或防火墙没放行网段。验证连通性的最小命令:

# 在 Nginx 机器上直接探后端 curl -w "connect=%{time_connect} total=%{time_total}\n" http://10.0.1.11:8080/healthz # connect 值高 → 网络或防火墙问题;total 高 → 后端本身慢

这个 time_connect 与 time_total 的拆分,是判断 504 该修网络还是修超时参数的最快证据。

代理职责的边界同样要明确:Nginx 是转发者,不是业务的第二个实现。凡是开始在 Nginx 里写复杂业务逻辑(多层 if 判断用户身份、用 rewrite 模拟路由表)的团队,都在重演同一个错误——把应用层复杂度搬进配置层,失去类型检查、测试与日志。健康的分工是:Nginx 只做与业务无关的流量治理(转发、超时、限流、缓存),一切需要理解业务语义的决策留给应用。这条边界守住了,Nginx 的配置才能长期保持第二章追求的那种可读秩序。

本节要点回顾

  • 头部改写四件套(Host、X-Real-IP、XFF、Proto)是代理上线的最小完整集;
  • XFF 是追加链,真实 IP 在第一段,且存在伪造可能;
  • proxy_read_timeout 匹配最慢接口,慢接口单独放行;
  • proxy_pass 带不带斜杠决定前缀剥离,写配置时当成显式契约。

作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U