事情本身不复杂,线索都在日志里。PHP-FPM 的 request_slowlog_timeout 设成 5 秒,慢日志里每隔几分钟就出现一条执行 30 秒的脚本,堆栈停在 file_get_contents,调用的是第三方短信接口,站点并发一高整池进程全被占住。
第一反应是「default_socket_timeout 默认 60 秒,比业务能接受的久得多」,验证下来不成立。
排查方向其实有限,先把可能性排一排。file_get_contents 没带超时参数,对端不响应就一直挂着。还有一种是调用的是外网域名,DNS 解析慢的时候卡在解析阶段。
不容易想到的是,没有连接复用,每次请求都重新建 TLS 连接。
第一件事是看慢日志里卡住的具体函数
tail -50 /var/log/php-fpm/www-slow.log
然后确认 php.ini 里的默认超时值
grep -n default_socket_timeout /etc/php.ini
接着改成带超时的请求方式并实测
time curl --max-time 3 http://example.com/
等前面都确认过,再确认 fpm 池里的进程不再被长期占住
ps -o pid,etime,cmd -C php-fpm | sort -k2 -r | head
怎么算真的好了,看的是同一批现象。慢日志不再出现 30 秒级别的记录,第三方接口抖动时页面最多延迟 3 秒,php-fpm 的 active 进程数回落。
这里还有个坑。业务代码里所有外部调用都要有超时和重试上限,php.ini 的默认值只是兜底;改完用压测把最坏路径跑一遍。拖得越久,排查成本越高,因为现场状态会被后续操作覆盖。
