PHP 超时三兄弟:max_execution_time、request_terminate_timeout、fastcgi_read_timeout

来源:互联网 时间:2026-09-06

一个长耗时接口,前端等到 504,可 PHP 的 error_log 里干干净净什么都没有。这种“网关报错、应用无日志”的组合拳,十有八九是超时链路上某一环先掐断了连接。PHP 站点的超时参数有三个,分属三层,谁先到点谁动手,报的错还不一样,搞混了排查方向就全错。

三兄弟各自管一段:max_execution_time 是 PHP 自己的闹钟,默认 30 秒,到点 PHP 主动 fatal,日志里会写 Maximum execution time exceeded;request_terminate_timeout 是 FPM 的闹钟,到点直接把 worker 进程杀掉,Nginx 会收到一个非正常断开,报 502;fastcgi_read_timeout 是 Nginx 的闹钟,默认 60 秒,FPM 一直不吭声,Nginx 等到超时就报 504。所以:有 PHP 日志是 PHP 层超时,502 大概率 FPM 杀进程,504 大概率 Nginx 等烦了。

# 第一层:php.ini(PHP 执行超时,默认 30s;CLI 下默认 0 不限时)
max_execution_time = 120

# 第二层:php-fpm.conf 的 www.conf(FPM 强杀,与上面对齐)
request_terminate_timeout = 120s
# 杀进程时会写日志,开启便于确认是不是它干的:
request_slowlog_timeout = 5s
slowlog = /var/log/php-fpm/www-slow.log

# 第三层:nginx 的 fastcgi 超时(等 FPM 响应,默认 60s)
location ~ \.php$ {
fastcgi_read_timeout 120s;
fastcgi_pass 127.0.0.1:9000;
}

有个反直觉的细节必须说:max_execution_time 统计的是脚本 CPU 执行时间,不含 sleep()、数据库等待、stream 操作这些“挂着不干活”的时间。这就是为什么你配了 30 秒,一个 sleep(60) 的脚本照样跑完——PHP 闹钟只数它真正干活的时长。而 FPM 和 Nginx 的两个超时数的是真实墙钟时间,该到点就到点。

# 用一个 sleep 脚本实测三层谁先动手(max_execution_time 不会截断它)
// test_timeout.php: <?php sleep(90); echo "done\n";

# 场景A:php=30s, fpm=120s, nginx=60s
curl -s -o /dev/null -w "%{http_code} %{time_total}s\n" https://站/test.php
# 预期:604,即 Nginx 60 秒等烦了报 504

# 场景B:php=30s, fpm=45s, nginx=60s
# 预期:45 秒左右 502——FPM 先动手杀了 worker

# 修改后统一重载
php-fpm -t && systemctl reload php-fpm
nginx -t && systemctl reload nginx

排查这类问题时,三个值拉出来对齐是第一步:php -i | grep max_execution_time、grep request_terminate_timeout www.conf、nginx -T | grep fastcgi_read_timeout,三个数值谁最小谁先触发。原则上要么后层大于前层(Nginx > FPM > PHP),让错误尽可能在应用层暴露并留下日志;要么主动在业务代码里对长任务改异步——导出、批量处理这类活,丢队列里慢慢跑,比把三兄弟的闹钟全调到 300 秒体面得多。

调大超时是解药也是毒药:闹钟调长意味着出问题的请求会占着 worker 更久,几个慢请求就能把进程池耗尽,把 504 升级成全站 502。每调一次都要盯着 FPM 的 active processes 曲线看一段时间。

相关阅读:超时是四层都可能出现的问题。《服务器故障排查总纲:按现象反查的五层定位法》把 504、慢查询和本篇的三个超时参数串成一条时间线,总纲定层、本篇调参,配合使用。

相关文章

标签:

A5创业网 版权所有