从状态码开始分支
502 与 504 是两件事:502 表示网关无法从上游得到有效响应,多为连不上上游或上游提前关闭连接;504 表示读取上游响应超时,即后端处理太久。先按状态码和错误日志分方向,再决定动作。很多人的第一反应是把 proxy_read_timeout 调大,但如果后端每次都稳定在 40 秒,把超时从 30 秒提到 60 秒只是把「快失败」改成了「慢成功」,连接与线程反而堆积得更多。
基本信息
| 适用组件 | Nginx 反向代理(HAProxy、云 SLB 语义相近) |
|---|---|
| 关键配置 | proxy_connect_timeout、proxy_send_timeout、proxy_read_timeout、proxy_next_upstream |
| 日志定位 | /var/log/nginx/error.log 中的 upstream 相关报错 |
| 关键变量 | $upstream_status、$upstream_response_time、$upstream_addr |
| 权限要求 | 读取日志需相应文件权限 |
典型使用场景
- 发布后突然大量 502:确认后端进程是否在监听、是否有健康检查摘除
- 业务高峰期 504 增多:先看后端真实耗时,而不是直接调超时
- 偶发 502:结合 $upstream_addr 判断是否集中在某一台后端
- 前后端连接被提前关闭:检查代理与后端两侧的 keepalive 与超时设置是否错配
- 客户端侧 499 增多:说明用户先放弃,根因仍多半是后端慢
错误日志与配置
错误日志与配置
tail -100 /var/log/nginx/error.log | grep -E 'upstream timed out|connect\(\) failed|upstream prematurely closed'
# 建议在 access log 中记录关键变量,便于分实例判读
# log_format main '$remote_addr [$time_local] "$request" $status '
# '$request_time $upstream_response_time $upstream_status $upstream_addr';
# 代理超时配置示例(按后端实际 P99 设定,不要凭感觉调大)
# proxy_connect_timeout 3s;
# proxy_send_timeout 30s;
# proxy_read_timeout 30s;
# proxy_next_upstream error timeout http_502 http_504; # 仅在幂等请求上放开重试状态与含义对照
| 状态码 / 日志 | 含义与方向 | 下一步 |
|---|---|---|
| 502 Bad Gateway | 连不上上游或上游提前关闭连接 | 确认后端监听、进程存活与连接复用配置 |
| 504 Gateway Timeout | 读上游响应超时,后端处理太久 | 查 $upstream_response_time 与后端内部耗时 |
| connection refused | 上游端口未监听 | 服务挂掉或正在重启 |
| upstream prematurely closed | 上游中途关闭连接 | 排查后端崩溃、被 OOM 杀或主动断连 |
| 499(客户端关闭连接) | 客户端等不及先断开 | 根因通常仍是后端慢,需向后排查 |
调整 proxy_read_timeout 之前,先用 $upstream_response_time 看后端的真实耗时分布:如果后端稳定超过原超时值,调大只是把问题从「失败」变成「更慢的成功」。