凌晨一点十七分,手机在床头柜上震得像得了帕金森,客户语音带着哭腔:“大哥,网站全白了,宝塔面板显示CPU跑满,日志里全是报错!”我眯着眼打开笔记本,心想又是哪个倒霉蛋把缓存目录权限搞崩了,结果这一查,差点把我自己的头发薅光。
第一幕:日志界面“口吐莲花”
登录宝塔面板,点开“日志”菜单——好家伙,错误日志一秒钟刷三屏,全是[error] 3274#0: *12345 FastCGI sent in stderr: "PHP message: PHP Fatal error: Uncaught Error: Call to undefined function mysql_connect()",我盯着“mysql_connect”愣了三秒,这年头还有哪个活爹用PHP5的老古董写法?再细看时间戳——当前时间明明是2025年,日志时间却是2023年,而且CPU负载曲线像心电图锯齿状狂跳。
宝塔日志查看的鬼打墙三小时—记一次被伪报错支配的深夜
排查Step1:先看实时错误日志
我习惯性点开“网站-设置-配置文件”,把error_log /www/wwwlogs/xxx.com.error.log;路径复制出来,用SSH执行tail -50,结果屏幕上蹦出来的还是那一堆“Call to undefined function”,但我用grep -c数了下,这文件里错误数量居然超过10万条——磁盘快被日志塞满了,这本身就是大问题。
踩坑转折点:我差点被日志骗了
按照经验,我第一反应是网站程序被植入了恶意脚本,否则不会有这么多重复报错,于是用find /www/wwwroot/xxx.com -name "*.php" -mtime -1找今天改动的文件,结果一个都没改,然后我又SB地去查PHP扩展,php -m里明明有mysqli和pdo_mysql,但宝塔面板的PHP设置界面里,这两个扩展的开关按钮是灰色的——这是典型的面板配置与CLI命令行配置不同步。
真相大白:日志文件“张冠李戴”
最后我灵机一动,去看了网站日志文件的inode(文件系统身份标识),执行ls -li /www/wwwlogs/xxx.com.error.log,显示inode是883423,再用lsof +L1查,发现有一个已删除但被进程占用的旧文件,inode也是883423。原来真正的错误日志早被logrotate(日志轮转)重命名成.gz压缩包了,但这个网站配置里硬编码了旧的绝对路径,导致Nginx把新的错误写进了一个已经删除的“幽灵文件”,而宝塔面板显示的,是那个被轮转下来的旧日志的缓存内容——所以时间戳才停留在2023年。
解决办法(极简版)
- 在宝塔面板“网站-设置-配置文件”里,把
error_log路径改成带new后缀的新文件(如xxx.com.new.error.log),保存并重载Nginx。 - 然后进SSH执行
ldconfig或直接reboot php-fpm(面板里点重启也行),确保新日志落盘。 - 这时候访问网站,如果还报错,再看新日志文件,错误就变成“
mysqli_connect(): Connection refused”——这才是真凶:MySQL服务挂了。
为什么我一开始没发现?
因为宝塔面板的“日志查看器”有1MB缓存,而且它默认读取的是/www/wwwlogs/下所有.log文件的合并视图,并不是实时tail,当有海量旧日志堆积时,面板的查询接口会优先展示磁盘上已有的文件内容,而新的日志写入被DDOS流量或异常进程挤到队尾——这造成了“日志在刷屏”的假象,实际上全是历史垃圾。
预防建议(血泪总结)
- 每天定时清空旧日志:宝塔面板“计划任务”里写个shell脚本,
find /www/wwwlogs/ -name "*.log" -mtime +7 -exec truncate -s 0 {} \;,别用rm,否则Nginx会写进“幽灵文件”。 - 关闭面板日志缓存:设置-面板设置-日志策略,把“显示最大条数”调成500,避免加载几万条历史记录导致界面卡死。
- 监控磁盘队列:如果日志量大,加一个
logrotate配置,把每个日志文件大小限制在20MB,压缩保存30天。 - 最重要:PHP-FPM错误日志别和网站访问日志放一起,分开路径,否则排查时你会被请求日志淹没。
那晚最后,我重启了MySQL服务,网站20秒恢复,客户问怎么回事,我只回了句:“日志它自己会说话,但有时候它说的是方言。”挂电话前补了一句:“记得明天把PHP版本从5.6升到8.1——不然下次就不是‘undefined function’,是‘undefined soul’了。”
(完)



发表评论