发布时间:2026-09-16 12:32 更新时间:2026-09-16 12:32 阅读量:0
后台导出报表、批量采集、生成大站点地图,这类耗时任务最容易触发超时。很多人第一反应是把 php.ini 里的 max_execution_time 调到 300,结果页面照样报 504;又有人去改 Nginx,改完变成 502。原因在于请求要穿过三层:Nginx 等 PHP-FPM 应答、PHP-FPM 等 PHP 脚本执行、PHP 自己限制脚本运行时长,任何一层先到点,请求就断。本文把这三处的职责、配置位置和取舍讲清楚,照着调一遍,基本能定位到是哪一层在掐断请求。
第一层是 Nginx。Nginx 把请求通过 FastCGI 协议转给 PHP-FPM 之后,会等待 FPM 返回响应头。等待多久由 fastcgi_read_timeout 决定,默认值 60 秒。注意它统计的是「两次读操作之间的间隔」,不是整个请求的总时长,所以一个持续输出内容的脚本即使跑很久,只要数据在流动就不会被判定超时。同组的还有 fastcgi_connect_timeout(连接 FPM 的超时)和 fastcgi_send_timeout(向 FPM 发送请求的超时),日常调优基本只动 read 这一个。
第二层是 PHP-FPM。进程池里有个 request_terminate_timeout,它是 FPM 对单个子进程处理单个请求的总时长硬限制,超时后 FPM 会直接 kill 掉这个子进程并记录一条 WARNING 日志。它的作用是兜底:防止某个脚本卡死(比如卡在外部接口或 DNS 解析上)把 worker 长期占住,最终耗尽整个进程池。该参数默认是 0,表示不限制,此时进程会一直等下去,风险要自己评估。
第三层是 PHP 自身。php.ini 里的 max_execution_time 限制脚本自身的 CPU 执行时间。需要留意的是,它不统计 sleep、数据库等待、网络 IO 等阻塞时间,所以在 Linux 上它管不住「等外部接口」这类场景,真正能拦住这种请求的是 FPM 的 request_terminate_timeout。CLI 模式下该值默认多为 0,即不限制,具体以官方文档和实际环境为准。
三者的关系可以这样理解:Nginx 决定客户端等不等得到结果,FPM 决定进程被占用多久,PHP 决定脚本自己跑多久。三者都小于任务实际耗时,请求必断;只放开其中一层,另外两层仍会先到点。
Nginx 侧建议写在 location ~ \.php$ 块里,或者放到单独的 fastcgi_params 片段中统一维护:
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_connect_timeout 10s;
fastcgi_send_timeout 120s;
fastcgi_read_timeout 120s;
}
PHP-FPM 侧在进程池配置里设置,路径通常是 /www/server/php/版本号/etc/php-fpm.d/www.conf 或 /etc/php-fpm.d/www.conf,以实际环境为准:
; 单个请求最长执行 120 秒,超时后由 FPM 结束该子进程
request_terminate_timeout = 120s
; 单个子进程处理多少请求后重启,避免内存缓慢增长
pm.max_requests = 500
; 慢日志有助于定位卡住的脚本
request_slowlog_timeout = 10s
slowlog = /var/log/php-fpm/www-slow.log
php.ini 侧对应调整:
max_execution_time = 120
max_input_time = 120
取值思路是「外层略大于内层」。比如任务预计跑 90 秒,PHP 给 120 秒,FPM 给 120 秒,Nginx 给 130 秒。这样正常情况下由 PHP 先结束并返回结果;万一 PHP 卡死,FPM 兜底清理进程;万一 FPM 也异常,Nginx 断开客户端等待,避免浏览器一直转圈。反过来把 Nginx 设得比 FPM 小,请求会先被 Nginx 判定超时,用户看到 504,而后台脚本可能还在跑,白白占用资源。
配置改完必须重载才生效,Nginx 用 nginx -t 校验后再 reload,FPM 用 kill -USR2 或 systemctl reload 平滑加载:
nginx -t && nginx -s reload
php-fpm -t
systemctl reload php-fpm
确认生效值,注意 FPM 模块可能覆盖 php.ini
php -i | grep -E "max_execution_time|Loaded Configuration"
排查时先看错误日志定位是哪一层在报错。Nginx 的错误日志里出现 upstream timed out 通常是 FPM 侧没按时返回;出现 recv() failed 或连接被重置,往往对应 FPM 杀掉了子进程。FPM 日志里出现「execution timed out」就是 request_terminate_timeout 触发的。
tail -f /var/log/nginx/error.log
tail -f /var/log/php-fpm/error.log
查看进程池是否被占满
ps aux | grep php-fpm | wc -l
几个常见坑:一是宝塔等面板会生成独立的 FPM 配置文件,手动改 php.ini 可能被面板覆盖,建议在面板的 PHP 设置里改;二是 PHP 的 set_time_limit() 只能延长不能缩短,且不影响 FPM 的硬限制,两者别混用;三是 Nginx 有多个 location 或 include 了公共片段时,可能出现后者覆盖前者的顺序问题,改完用 nginx -T 输出完整配置核对;四是长任务优先拆成异步队列或后台进程处理,把前端请求控制在秒级返回,比一味加大超时值更稳妥,也更能保护进程池。
最后提醒一点:超时值放得越大,单个卡死请求占用 worker 的时间就越长,高并发下反而更容易拖垮整站。把 request_slowlog_timeout 打开、定期看慢日志,找出真正耗时的脚本去优化,比单纯调参数更有价值。改完记得压一轮,观察 FPM 的活跃进程数和 504 比例是否回落,再决定是否继续微调。
| 📑 | 📅 |
|---|---|
| 宝塔PHP扩展装不上怎么办:编译报错与权限排查 | 2026-09-16 |
| 宝塔面板MySQL与PHP版本切换:兼容性检查、扩展重装与白屏处理 | 2026-09-16 |
| WordPress固定链接改版后老链接404:rewrite与301重定向保住收录 | 2026-09-16 |
| CDN回源配置怎么填:回源Host、回源协议与真实IP排查 | 2026-09-16 |
| 宝塔面板计划任务做网站自动备份:数据库与文件打包、异地存储配置 | 2026-09-15 |
| WordPress多站点网络搭建:子域名与子目录怎么选、域名映射与迁移注意点 | 2026-09-16 |
| 域名解析生效慢与解析被劫持:TTL、DNSSEC与本地缓存排查 | 2026-09-16 |
| 服务器时间不对导致HTTPS报错与定时任务错乱:ntp/chrony校时与宝塔同步配置实操 | 2026-09-16 |
| 宝塔面板网站防跨站攻击open_basedir怎么配:报错原因、目录放行与多站隔离实践 | 2026-09-17 |
| 网站被恶意刷流量刷接口怎么办:Nginx限速与IP封禁配置思路 | 2026-09-17 |