凌晨两点十七分,手机在床头柜上震得嗡嗡响,我摸黑抓过手机,屏幕上是客户发来的十几条消息:“老张,官网打不开了”“后台提示数据库连接失败”“数据会不会丢啊”,我叹了口气,打开电脑连上服务器,屏幕上红彤彤一片报警——宝塔面板里的MySQL服务显示“运行中”,但网站全部500错误。
这就是运维人的日常,今天不聊高大上的架构设计,就说说昨晚这次真实踩坑经历,把排查思路完整拆给你看,顺便骂两句宝塔某些反人类的默认设置。
宝塔面板半夜抽风,MySQL连不上了?这份救火指南帮你省下两小时
先看一眼报错截图: 宝塔面板MySQL状态页显示“运行中”,但点击“停止”按钮没反应,强制重启后提示“MySQL服务启动失败”,日志文件里刷出三行刺眼的红字:
[ERROR] InnoDB: Unable to lock ./ibdata1, error: 11
[ERROR] InnoDB: Operating system error number 11 in a file operation.
[ERROR] InnoDB: Error number 11 means 'Resource temporarily unavailable'
看到这个错误,懂行的人已经能猜个八九不离十了——文件锁冲突,但别急,我当时第一反应是磁盘满了,赶紧敲了句命令:
df -h && df -i
结果磁盘空间还剩42%,inode也没爆,那就接着查进程,ps aux | grep mysql 发现有两个mysqld进程在跑,一个PID是旧的,僵在那里不动,宝塔的“运行中”状态判断逻辑是看PID文件是否存在,这设计就离谱——进程早死了,PID文件还留着,面板就自欺欺人地标绿。
这才是真正的坑: 宝塔自带的MySQL守护脚本有个bug,当MySQL遭遇OOM(内存不足)被系统kill掉后,它会重复拉起新进程,但旧的socket文件没清理干净,导致新进程起不来,我翻了下系统日志,果然看到之前有个OOM-killer的痕迹——内存预算超了,MySQL被强制杀掉,然后宝塔的守护脚本疯狂重启,就卡在“锁文件”这一步死循环。
排查到这,方案就很清晰了,第一步,先手动干掉所有残留进程:
pkill -9 mysqld rm -f /www/server/data/mysql.sock.lock rm -f /www/server/data/ibdata1.lock
第二步,检查宝塔的守护脚本配置,路径在 /www/server/panel/plugin/mysql_protect 下面,我直接把 start_mysql.sh 里的“自动重启间隔”从默认的5秒改成60秒,又给脚本加了个判断:如果发现已有mysqld进程存活超过3分钟,就不再强制拉起。这就是从根源上防止“反复横跳”式启动。
第三步,治本,这次OOM的诱因是PHP-FPM占用内存太高,宝塔默认把PHP的pm.max_children设为自动,但实际跑起来能给你吃满2G内存,我改成固定值,按每进程40M估算,128M内存就设4个,512M就设10个,留出余量给MySQL,同时临时加了两行swap:
fallocate -l 2G /swapfile chmod 600 /swapfile mkswap /swapfile && swapon /swapfile
重启MySQL之前,我还顺手做了个备份——别嫌麻烦,这次没出数据问题不代表下次不会。mysqldump -u root -p --all-databases > /backup/all_$(date +%F).sql 跑完后,正式执行:
/etc/init.d/mysqld start
看到 [ OK ] 那一刻,我长舒一口气,网站恢复访问,客户发来一个“辛苦了”,我盯着屏幕上的宝塔面板,绿色状态灯亮得刺眼。
最后说几个防踩坑建议,都是拿血泪换的:
- 别信面板的“运行中” ——用
netstat -tlnp | grep 3306和ps aux | grep mysqld双重确认,面板状态只能做参考。 - OOM-killer是隐形杀手 ——宝塔默认不swap,赶紧加上,不然内存稍有波动MySQL就是第一个被祭天的。
- 锁文件不清理,你就永远卡在启动失败 ——
/www/server/data/目录下的.lock和.sock文件,出问题时先清这个。 - 日志别只看MySQL的 ——
/var/log/messages里查oom和killed process,能帮你提前发现内存失控。
这行当就是这样,白天看你光鲜亮丽写代码,半夜谁蹲在机房吹冷风谁知道,但能把踩过的坑写出来让别人避开,也算值了,下次要是你宝塔面板也抽这个风,直接翻这篇,省下两小时折腾时间,陪老婆孩子多聊会天,不香吗?



发表评论