Nginx 502 与 504 的分层排查:到底卡在哪一段

502 和 504 的报错页面长得差不多,但原因几乎相反:502 Bad Gateway 是「上游给了无效响应」,504 Gateway Timeout 是「等上游等到超时」。先分清这两者,能省一半排查时间。

错误码含义直接原因
502上游返回了无法解析的响应,或连接被断开上游进程崩了 / 假死 / 端口没监听 / 连接被重置
504上游在规定时间内没响应上游处理慢(慢查询、死锁、外部 API 慢)
503Nginx 自身拒绝服务超出 worker_connections、维护中
499客户端主动断开用户等不及关页面了(不是 Nginx 的问题)

第一步:先确认是哪一层挂了

别一上来就改 Nginx 配置。先确认上游服务本身是否活着。

# 1. 从宿主机直连上游(绕过 nginx)
curl -v http://127.0.0.1:9000/            # PHP-FPM
curl -v http://127.0.0.1:8080/health      # 后端应用

1. 2. 上游端口是否在监听
ss -lntp | grep -E ':9000|:8080'

1. 3. 若上游是容器,从 nginx 容器内部测(网络隔离常被忽略)
docker exec <nginx容器> curl -sv http://<上游容器名>:8080/health

1. 4. 看上游进程数
ps aux | grep -c "[p]hp-fpm"

第 3 步最容易发现问题:宿主机 curl 通了,但从 nginx 容器 curl 不通——那是容器网络问题(不在同一网络、IP 变了、DNS 解析失败),跟 Nginx 配置无关。

第二步:读 error.log 的关键字段

error.log 每条记录都带 upstream 状态,这是定位的核心。

tail -50 /var/log/nginx/error.log

1. 典型 502
1. upstream prematurely closed connection while reading response header
1.   from upstream, client: 1.2.3.4, request: "GET / HTTP/1.1",
1.   upstream: "fastcgi://172.26.0.13:9000"

1. 典型 504
1. upstream timed out (110: Connection timed out) while reading
1.   response header from upstream, upstream: "http://172.26.0.11:8080"
日志关键词指向哪里下一步
prematurely closed connection上游主动断连(崩溃或自杀)查上游日志与进程状态
connect() failed (111: Connection refused)端口没监听上游没起来或监听地址错
no live upstreams全部上游被标记不可用健康检查把上游全判死了
timed out (110)上游处理超过阈值查上游是否在跑慢查询
upstream sent too big header上游响应头过大调 proxy_buffer_size
recv() failed (104: Connection reset)连接被 RST上游被杀或防火墙

第三步:504 专项——超时到底卡在哪

504 的本质是「Nginx 等不到」。要继续往下钻:上游自己是不是也在等它的后端?

# PHP-FPM 慢日志
1. php-fpm.d/www.conf:
1.   request_slowlog_timeout = 5s
1.   slowlog = /var/log/php-fpm/slow.log
tail -20 /var/log/php-fpm/slow.log

1. MySQL 慢查询
mysql -e "SHOW VARIABLES LIKE 'slow_query_log'"
mysql -e "SELECT * FROM mysql.slow_log ORDER BY start_time DESC LIMIT 5"

1. 看进程卡在哪个系统调用
strace -p $(pgrep -f "php-fpm: pool www" | head -1) -T 2>&1 | head -20

常见的 504 根因链条:

  • Nginx 等 PHP-FPM 30 秒 → PHP-FPM 在等 MySQL → MySQL 有锁等待:只调 Nginx 的 timeout 毫无意义,要解决 MySQL 的锁
  • PHP-FPM 进程池被占满:所有 worker 都在处理慢请求,新请求排队,表现为「有时 502 有时 504」
  • 外部 API 超时:应用调第三方接口没设超时,一路挂到底
  • DNS 解析慢:resolver 配置不当,每次请求都卡在解析

第四步:超时参数的优先级(最容易配错)

Nginx 的超时是一串,改错地方等于没改。

层参数默认说明
Nginx → 上游 建连proxy_connect_timeout / fastcgi_connect_timeout60sTCP 握手超时,内网应设很小(1-3s)
Nginx → 上游 发送proxy_send_timeout60s发请求体的超时
Nginx → 上游 读取proxy_read_timeout / fastcgi_read_timeout60s最常需要调的,等响应的上限
PHP-FPM 自身request_terminate_timeout0(不限)FPM 侧执行上限,比 Nginx 小才生效
PHP 脚本max_execution_time30sPHP 侧执行上限

关键规则:谁小谁生效。Nginx 的 read_timeout 设 300s,但 PHP 的 max_execution_time 是 30s,结果还是 30 秒 504——而且报错来自 FPM 而不是 Nginx,容易看错方向。

# 一次统一检查所有超时
grep -rE "connect_timeout|send_timeout|read_timeout|terminate_timeout" \
  /etc/nginx/ /etc/php*/ 2>/dev/null

php -i | grep -E "max_execution_time|max_input_time"

第五步:502 专项——PHP-FPM 假死

PHP-FPM 有一种特殊状态:进程都在,但全部卡死,不接新请求。日志看不到崩溃,表现为 502。

# 1. 看 FPM 状态(需先开 status page)
curl http://127.0.0.1/status?full
1. pool: www  process manager: dynamic
1. active processes: 5 (max 5)      ← 满了
1. listen queue: 20 (max 128)       ← 有排队
1. max children reached: 2          ← 达到上限次数

1. 2. 看进程卡在哪个系统调用
for pid in $(pgrep -f "php-fpm: pool www"); do
  cat /proc/$pid/wchan; echo
done

1. 3. 用 strace 看具体阻塞点(会短暂暂停进程,谨慎)
strace -p <pid> -T 2>&1 | head -20
  • listen queue 有值 = 请求在排队,说明 worker 不够或都在处理慢请求
  • max children reached 增长 = 池子太小,要调 pm.max_children
  • 进程都在但 active=0 = 可能连不上后端(如 MySQL),在等连接超时
  • 重启 FPM 只是临时缓解:根因通常是慢查询或外部调用,不解决会复发

第六步:容器环境特有的坑

现象原因修复
宿主机 curl 通,nginx 容器不通容器不在同一 network都把服务挂到同一 network
IP 变了导致 502用默认 bridge,容器重建后 IP 改变用固定 IP 或按容器名解析
间歇性 502上游容器在重启中配 depends_on: service_healthy
连接被拒且日志有 111上游监听 127.0.0.1 而非 0.0.0.0改监听地址为 0.0.0.0
413 而非 502请求体超过 client_max_body_size调大该值(上传功能常见)
# 固定网段 + 固定 IP,避免容器重建后 IP 变化
networks:
  backend:
    ipam:
      config:
        - subnet: 172.26.0.0/24
services:
  nginx:
    networks:
      backend:
        ipv4_address: 172.26.0.10
  app:
    networks:
      backend:
        ipv4_address: 172.26.0.13

固定 IP 的价值:Nginx 配置里写 fastcgi_pass 172.26.0.13:9000 就不会因容器重建而失效。若依赖容器名解析,DNS 缓存与重启时序都会带来间歇性 502。

一张表记住判断顺序

现象先查再查最后查
502 + premature close上游进程存活?上游日志有无崩溃上游是否被 OOM 杀
502 + connection refused端口是否监听监听地址是否 0.0.0.0防火墙/网络隔离
502 + no live upstreams健康检查配置上游是否真不健康检查间隔是否过短
504超时参数谁最小上游慢日志上游在等什么(DB/外部 API)
502 与 504 交替FPM worker 是否满listen queue 是否堆积调 pm.max_children

总结

  • 先分清 502 和 504:一个是响应无效,一个是等超时,排查方向完全不同
  • 从 nginx 容器内部测上游:宿主机通不代表容器通,这是容器环境最常见误判
  • 504 要往下钻两层:Nginx 等 FPM,FPM 可能在等 MySQL——只调 Nginx 超时无效
  • 超时参数取最小值生效:Nginx 300s 但 PHP 30s,结果就是 30s 报错
  • 502 交替 504 = worker 池满,根因通常是慢请求,不是 Nginx 配置
暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇