加入收藏 | 设为首页 | 会员中心 | 我要投稿 航空爱好网 (https://www.ikongjun.com/)- 混合云存储、媒体智能、AI行业应用、应用程序集成、办公协同!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

PHP后端架构师私藏:3行代码秒定90%线上故障

发布时间:2026-10-20 08:02:04 所属栏目:PHP教程 来源:DaWei
导读:  去年春晚零点前十二分钟,监控弹出 PHP-FPM 子进程集体僵死——不是 502,是直接不接请求,Nginx 日志里连 upstream timeout 都没刷出来,只有一堆 upstream prematurely closed connection。我抄起键盘切到线上机,手指刚

  去年春晚零点前十二分钟,监控弹出 PHP-FPM 子进程集体僵死——不是 502,是直接不接请求,Nginx 日志里连 upstream timeout 都没刷出来,只有一堆 upstream prematurely closed connection。我抄起键盘切到线上机,手指刚敲完 ssh root@prod-03,张工在 Slack 里发:“你先别动,我正回滚 vendor/monolog,甲方说日志打太密。”


  我原以为是 monolog 写爆磁盘导致 fwrite() 卡死,结果 df -h 显示 /var/log 才用了三成;我原以为是 systemd 限了 MemoryLimit,systemctl show php-fpm | grep Memory 看着好好的。可当我蹲在 prod-03 的 tmux 里,把 tail -f /var/log/php7.4-fpm-slow.log 调出来,盯着那行慢日志的 timestamp 格式(2024-01-28T23:59:58.321045+08:00),突然想起上周五王总监提过一句:“能不能把日志时区统一成 UTC?现在看时间总得心算八小时。”——反正我也没改。


  就在这时,李哲冲进运维间吼了句:“快看 access.log!最后二十个请求全卡在 /api/v2/user/profile?!”我顺手 cat /var/log/nginx/access.log | tail -20,果然,全是 POST /api/v2/user/profile,status 全是 499,但 timestamp 是 23:59:57.999——比 slow.log 里第一条还早三百毫秒。我手指悬在键盘上顿了半秒,直接输:grep -E 'profile.23:59:5[789]' /var/log/nginx/error.log | head -1 ——出来一行:recv() failed (104: Connection reset by peer) while reading response header from upstream。再输:ps aux | grep 'php-fpm: pool www' | wc -l ——显示 17,但 ps aux | grep 'php-fpm: master process' 显示 master 进程 PID 是 1204,而 ls -l /proc/1204/fd | wc -l 回来是 1023……


  (刚才楼下保洁阿姨拖地,水渍漫到服务器机柜脚边了,我喊她别往这边推,她说“这不干你们的事嘛”。)


  我原以为是 fd 耗尽,结果 lsof -p 1204 | wc -l 是 608,和之前一样;我原以为是子进程被 signal 杀爆,strace -p 1204 只看见 endless epoll_wait。直到我把 tail -f /var/log/php7.4-fpm-slow.log 临时加了个 -n 1000,再刷新页面——慢日志第一行跳出来:[28-Jan-2024 23:59:58] [pool www] pid 15621 script '/var/www/html/api/v2/user/profile.php' executing with timeout 300s, reached 299.845s。等等,这个超时值……谁设的?查 php-fpm.d/www.conf,timeout=300 没动;查 nginx.conf,fastcgi_read_timeout 是 60——对不上。我又翻了下昨天上线的 config.yaml,里面写着 php_timeout_ms: 299845,是 JS 前端传来的整数……


  于是我把光标停在终端里,删掉所有命令,只留下三行:

文章配图,仅供参考

strace -p $(pgrep -f 'master process' | head -1) -e trace=kill,sigreturn -f 2>&1 | grep -E '(SIGKILL|SIGUSR2)'
lsof -i :9000 | grep ESTABLISHED | wc -l
curl -sI http://localhost:8000/api/v2/user/profile | head -1
第一行盯住信号,第二行看 FPM 还剩几个活连接,第三行试一次真实请求路径——不用 curl -v,不看 body,只看 HTTP/1.1 200 或 502 头本身是否出来。八秒钟后,第三行回显 HTTP/1.1 502,第二行是 0,第一行没信号。我直接 Ctrl+C,退了 shell,把笔记本合上。张工消息又弹出来:“回滚完了,恢复了。”我说:“没回滚的事,是 profile.php 里有个 new DateTime(‘now’, new DateTimeZone(‘Asia/Shanghai’)) 跟系统 timezone 不一致,PHP 初始化时卡在时区数据库加载,卡满 299 秒被自己 kill。”他说:“啥?那个 DateTimeZone 是你半年前写的。”——对,是我写的。我也不知道为啥偏偏今天崩。


  (茶水间微波炉响了第七次,每次都是热饭,没人拿。)


  优胜劣汰,不是说写得漂亮的人活下来,是那些在 error_log 里多留一行 timestamp、在 strace 前先 grep 一下 PID、在 curl 之后从不急着看 body 的人——活下来。但这次,三行代码定住了故障,却定不住为什么 DateTimeZone 加载要花两百九十九秒。有谁碰到过这个吗?

(编辑:航空爱好网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!