当 MySQL 被 OOM Killer 悄然杀死


(WordPress 数据库连接故障)

当 MySQL 被 OOM Killer 悄然杀死(WordPress 数据库连接故障)

摘要:某 WordPress 站点频繁出现“数据库连接错误”,服务器面板显示一切正常,但 MySQL 服务间歇性消失。通过日志分析,最终定位为 Linux 内存不足触发的 OOM Killer 强制杀进程所致。本文详述排查思路、证据链以及永久解决方案,适用于类似场景的运维参考。


1. 现象描述

  • 环境:Linux 服务器,运行 WordPress + MySQL(5.6.50),每日凌晨 1 点自动重启。
  • 故障表现:网站间歇性报错“数据库连接失败”,刷新后有时恢复,有时持续不可用。
  • 服务器面板:CPU、负载显示正常,但 MySQL 服务进程实际已消失。
  • 时间点:最近一次发生在 2026-08-04 23:58,距上次启动约 11 小时。

2. 初步排查:MySQL 日志未发现异常

首先检查 MySQL 错误日志(/www/server/data/主机名.err),尾部内容如下:

2026-08-04 12:31:19 1983 [Note] /www/server/mysql/bin/mysqld: ready for connections.
...(大量正常启动信息)
2026-08-05 00:01:24 25314 [Note] Plugin 'FEDERATED' is disabled.
2026-08-05 00:01:25 25314 [Note] InnoDB: Database was not shutdown normally!
2026-08-05 00:01:25 25314 [Note] InnoDB: Starting crash recovery.
2026-08-05 00:01:38 25314 [Note] /www/server/mysql/bin/mysqld: ready for connections.

关键发现:

  • 12:31 成功启动,但 00:01 再次启动时出现了 “Database was not shutdown normally”,说明上次关闭是非正常终止(不是 Normal shutdown)。
  • 而 12:30 那次关闭是正常的(Normal shutdown),但那是中午的事,与当前故障无关。

结论:MySQL 在某个时刻被强制杀死,未能记录正常的关闭日志。


3. 深入追踪:系统日志揭示真凶

使用 journalctldmesg 查看系统内核日志:

dmesg | grep -i "kill\|oom" | grep -i mysql

输出:

[10987.992714] Out of memory: Killed process 1983 (mysqld) total-vm:1393780kB, anon-rss:11864kB, file-rss:0kB, shmem-rss:0kB, UID:1002
[11017.872810] mysqld invoked oom-killer: gfp_mask=0x6280ca(...), order=0, oom_score_adj=0
[11018.093933] Out of memory: Killed process 9051 (mysqld) total-vm:209724kB, anon-rss:159352kB, file-rss:36kB, shmem-rss:0kB, UID:0

同时,/var/log/messages 中也存在多次类似记录(8月2日、8月4日均有)。

确凿证据

  • OOM Killer(Out-Of-Memory Killer)是 Linux 内核在物理内存耗尽时,强制选择并杀死某些进程以恢复系统的机制。
  • 本次故障正是由于系统内存耗尽,内核主动杀死了 MySQL 进程,导致服务中断。

4. 为什么“几年只发生几次”?

并非每次启动都会触发 OOM,而是取决于当时的内存竞争情况:

  • 流量波动:访问高峰或搜索引擎爬虫会导致 PHP 进程增多,内存占用上升。
  • 定时任务:如备份、日志轮转等,可能在特定时刻瞬时消耗大量内存。
  • 内存泄漏:WordPress 插件或主题可能存在缓慢的内存泄漏,运行数小时后累积到危险线。
  • 并发 SSH 攻击:日志中出现大量来自 43.156.253.91 的暴力破解尝试,虽然本身不致命,但会额外消耗系统资源。

上述因素叠加,在偶发时间点达到内存阈值,触发 OOM Killer。


5. 排除人为操作

检查历史命令和登录记录,确认没有用户手动执行过 service mysqld stopkill 命令:

history | grep -i "mysql\|stop\|shutdown"
# 只输出了一些查询命令,无停止操作

last -a | head -20
# 检查登录 IP 和时间,未发现异常

因此,故障纯属系统自动保护行为,非人为误操作或攻击导致


6. 永久解决方案

根本思路:增加可用内存或降低应用内存消耗,使系统不再达到 OOM 阈值。

6.1 立即增加 SWAP 虚拟内存(最快速有效)

# 创建 2GB swap 文件
dd if=/dev/zero of=/swapfile bs=1M count=2048
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile

# 永久生效
echo '/swapfile none swap sw 0 0' >> /etc/fstab

# 验证
free -h

6.2 优化 MySQL 内存配置

编辑 MySQL 配置文件(/etc/my.cnf 或宝塔面板配置),调整以下参数:

[mysqld]
innodb_buffer_pool_size = 64M        # 根据物理内存调整,建议不超过50%
max_connections = 50                  # 降低并发连接上限
tmp_table_size = 16M
max_heap_table_size = 16M
query_cache_size = 0                  # 5.6 版本建议关闭
query_cache_type = 0
performance_schema = OFF              # 节省内存

重启 MySQL:

systemctl restart mysqld

6.3 优化 PHP-FPM(如有)

若使用 PHP-FPM,适当调低 pm.max_children(如设为 20~30),减少 PHP 进程总数。

6.4 启用 WordPress 缓存插件

安装静态缓存插件(如 WP Super Cache),减少动态 PHP 执行和数据库查询,降低内存占用。

6.5 安全加固:防御 SSH 暴力破解

安装 fail2ban 并修改 SSH 默认端口,减少无效连接对系统资源的消耗。


7. 验证与监控

  • 执行上述优化后,观察 /var/log/messagesdmesg 是否再出现 OOM 记录。
  • 可设置简单的内存监控脚本(如当可用内存低于 200MB 时发送告警),以便及时干预。

8. 结语

Linux OOM Killer 是保障系统整体稳定的最后一道防线,但对于数据库等关键服务,被误杀会带来业务中断。通过本次排查,我们展示了如何从表象深入到内核日志,定位根因,并提供了低成本、高回报的解决方案。增加 SWAP 和优化应用内存配置,足以应对大多数间歇性内存不足场景。

维护提醒:定期检查系统日志、监控内存趋势,是预防此类问题的良好习惯。


本文基于真实故障案例撰写,环境为 CentOS 7 + MySQL 5.6 + WordPress,适用于类似 LAMP/LNMP 架构。

封面

声明:三二一的一的二|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - 当 MySQL 被 OOM Killer 悄然杀死


三二一的一的二