PHP-FPM捕获request_terminate_timeout触发的SIGTERM并记录日志
解决PHP-FPM超时SIGTERM信号日志追踪问题
方案1:结合PHP-FPM慢日志与脚本主动超时检测
配置层面启用慢日志
在PHP-FPM的pool配置文件(如www.conf)中添加以下设置,追踪接近超时的请求:
request_slowlog_timeout = 30s ; 与request_terminate_timeout保持一致或稍短 slowlog = /var/log/php-fpm/slow_requests.log request_terminate_timeout = 30s
当请求运行时长超过request_slowlog_timeout时,PHP-FPM会自动将请求的调用栈、URI、客户端信息等写入慢日志,可直接定位超时请求。
脚本内主动埋点检测
在业务代码的耗时操作节点(循环、外部API调用等)添加超时检查,提前记录日志并主动退出:
$startTimestamp = microtime(true); $timeoutBuffer = 2; // 预留2秒缓冲,避免被强制终止 $maxRuntime = 30 - $timeoutBuffer; // 对应request_terminate_timeout的值 // 示例:耗时循环操作 while (true) { $elapsed = microtime(true) - $startTimestamp; if ($elapsed >= $maxRuntime) { error_log("[超时预警] 请求URI: {$_SERVER['REQUEST_URI']} 运行时长{$elapsed}s,即将被终止"); exit(1); // 主动退出,触发register_shutdown_function执行 } // 业务逻辑代码 }
主动退出时register_shutdown_function会正常执行,可在该函数中补充标准化的终止日志。
方案2:通过PHP-FPM访问日志筛选超时请求
调整访问日志格式
修改PHP-FPM pool配置的日志格式,加入请求处理时长字段:
access.log = /var/log/php-fpm/access.log access.log.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C"
其中%{mili}d代表请求处理时长(单位毫秒),%r为请求URI。
日志筛选脚本
编写shell脚本定时扫描访问日志,提取处理时长超过阈值的请求:
#!/bin/bash TIMEOUT_THRESHOLD=30000 # 对应30秒超时,单位毫秒 ACCESS_LOG="/var/log/php-fpm/access.log" TIMEOUT_LOG="/var/log/php-fpm/timeout_terminations.log" # 筛选出处理时长超过阈值的请求,追加到超时日志 grep -E " [0-9]{5,} " $ACCESS_LOG | awk -v threshold=$TIMEOUT_THRESHOLD '$10 > threshold {print strftime("[%Y-%m-%d %H:%M:%S]"), $0}' >> $TIMEOUT_LOG
可通过crontab定时执行该脚本,实现自动化的超时请求日志汇总。
方案3:利用连接状态检测(有限适用)
开启ignore_user_abort并结合connection_status判断请求终止原因,仅在进程未被立即杀死时生效:
ignore_user_abort(true); register_shutdown_function(function() { if (connection_status() !== CONNECTION_NORMAL) { error_log("[异常终止] 请求URI: {$_SERVER['REQUEST_URI']} 连接状态异常,疑似超时被SIGTERM终止"); } });
注意:若PHP-FPM直接发送SIGKILL(部分场景下SIGTERM未生效时会触发),该方案无法捕获。
内容的提问来源于stack exchange,提问作者zer0uno
相关产品推荐
相关产品推荐

