先把当时的情况摆出来。站点跑在 PHP 8.1 加 Nginx 上,白天蜘蛛请求的 P95 响应时间 4 秒,error.log 里不断出现 pool www seems busy 的告警,用户侧只是偶尔卡一下。
原因不止一个,得分开看。pm 设成 dynamic 但 max_children 只有 8,扛不住并发。另一种情况是某个插件在每页都发起外部 HTTP 请求,单次卡三秒。
不容易想到的是,慢查询把连接占住,进程一直不释放。还有一种情况,opcache 关闭,每次请求都重新编译模板。
动手时先看告警的密集程度和时段
grep 'seems busy' /var/log/php-fpm/error.log | awk '{print $1,$2}' | uniq -c | tail
随后统计各进程的累计耗时找出慢请求
ps -eo pid,etimes,cmd | grep 'php-fpm: pool' | sort -k2 -rn | head
接着打开慢日志定位具体页面
request_slowlog_timeout = 3s
slowlog = /var/log/php-fpm/slow.log
剩下的就是按内存实测结果调大进程数
pm = static
pm.max_children = 32
我习惯把每一步的执行时间和结果记在一边,后面复盘省事。
别只看报错消失,验证要多做一步。进程池调整并去掉页面里的同步外部请求后,pool busy 告警不再出现,蜘蛛请求的 P95 回到 400ms 以内。
提醒一点。max_children 要按单进程内存乘出总量来算,盲目调大可能把内存吃光,先量再改。如果同一现象隔几天又出现,说明根因没找到,别当偶发处理。
