当前位置:首页>Linux>数据库被杀:Linux OOM Killer 应急处置全记录

数据库被杀:Linux OOM Killer 应急处置全记录

  • 2026-09-10 05:35:21
数据库被杀:Linux OOM Killer 应急处置全记录

摘要: 每个运维工程师都经历过这样的时刻:凌晨被告警电话叫醒,核心数据库进程"消失"了,业务全线瘫痪。这篇文章不是教科书,是我这些年处理 OOM 故障的实战手册——从发现问题的第一秒,到彻底解决,每一步都经过实战检验。


凌晨4点17分,手机震动。

打开监控一看,MySQL 进程"没了"。

不是挂了,是"消失"了——进程列表里找不到,端口也监听不到。

那一刻,我相信每个运维人都懂——心跳加速,手心冒汗,脑子里闪过无数个"完了完了"。

但别慌。

这些年,我处理过不下五十次类似的故障。今天把这套 OOM 应急处置流程分享给你,不是教科书那种理论,是真正能救命的实战经验。

01 第一步:确认是不是 OOM Killer 干的

很多人一看到进程"消失",第一反应是"程序崩了"或者"被黑客攻击了"。

先别急着下结论。

Linux 系统有个机制叫 OOM Killer(Out Of Memory Killer),当系统内存耗尽时,内核会自动选择占用内存最多的进程"杀掉",以保护系统不崩溃。

怎么确认是不是 OOM Killer 干的?

方法1:查看内核日志

dmesg | grep -i "oom\|killed process"

如果你看到类似这样的输出:

[12345.678] Out of memory: Kill process 12345 (mysqld) score 900 or sacrifice child[12345.679] Killed process 12345 (mysqld) total-vm:8192000kB, anon-rss:7340032kB

实锤了,就是 OOM Killer 干的。

方法2:查看系统日志

grep -i "oom\|killed process" /var/log/messages# 或者grep -i "oom\|killed process" /var/log/syslog

方法3:查看 journalctl(systemd 系统)

journalctl -k | grep -i "oom\|killed process"

记住:先确认问题,再解决问题。

02 第二步:紧急恢复服务

确认是 OOM 后,第一件事不是找原因,而是恢复服务。

业务不能等,用户不能等。

1. 重启被杀的进程

systemctl restart mysqld# 或者service mysql restart

2. 检查服务状态

systemctl status mysqld

3. 验证业务恢复

# 检查端口是否监听netstat -tlnp | grep 3306# 检查进程是否存在ps aux | grep mysqld# 测试连接mysql -u root -p -e "SELECT 1"

如果服务起不来,别死磕,先看看日志:

tail -f /var/log/mysqld.log

记住:紧急情况下,先恢复,再排查。

03 第三步:分析内存使用情况

服务恢复后,别松口气,问题还没解决。

现在要搞清楚:为什么会 OOM?

1. 查看当前内存使用情况

free -h

输出示例:

              total        used        free      shared  buff/cache   availableMem:           15Gi       8.2Gi       1.2Gi       234Mi       6.1Gi       6.5GiSwap:         2.0Gi       2.0Gi          0B

重点看三个指标:

  • used:实际被进程使用的内存
  • buff/cache:被内核用于缓冲和缓存的内存(这部分可以回收)
  • available:应用程序实际可用的内存(这才是关键)

如果 available 很低(比如低于 500MB),说明内存确实紧张。

2. 查看 Swap 使用情况

swapon --show

如果 Swap 使用率接近 100%,说明物理内存已经不够用了,系统在频繁使用虚拟内存。

Swap 不是万能的。 当系统频繁在物理内存和 Swap 之间倒腾数据时,性能会急剧下降,这叫"抖动"(thrashing)。

3. 查看内存占用前10的进程

ps aux --sort=-%mem | head -11

输出示例:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMANDmysql    12345  5.2 45.3 8192000 7340032 ?     Sl   03:15  12:34 /usr/sbin/mysqldjava     23456 12.5 23.1 4096000 3670016 ?     Sl   03:20   8:45 java -jar app.jarroot     34567  2.1  8.7 2048000 1409024 ?     Ss   03:10   5:23 /usr/bin/dockerd

重点看 %MEM 列和 RSS 列:

  • %MEM:进程占用内存的百分比
  • RSS:进程实际使用的物理内存(Resident Set Size)

找到那个占用内存最多的进程,它就是"罪魁祸首"。

04 第四步:深入分析根因

找到内存占用最高的进程后,要搞清楚:它为什么占用这么多内存?

情况1:内存泄漏

如果进程的内存占用在持续增长,从来不下降,很可能是内存泄漏。

怎么确认?

# 每隔10秒查看一次进程的内存占用watch -n 10 "ps -p 12345 -o pid,rss,vsz,comm"

如果 RSS 值在持续增加,说明有内存泄漏。

对于 Java 应用,可以抓取堆转储:

jmap -dump:format=b,file=heap.hprof 12345

然后用 MAT(Memory Analyzer Tool)或者 JProfiler 分析堆转储文件,找出哪些对象没有被释放。

情况2:配置不当

有时候不是程序有问题,而是配置不合理。

比如 MySQL:

# 查看 MySQL 的内存相关配置mysql -u root -p -e "SHOW VARIABLES LIKE '%buffer%';"

如果 innodb_buffer_pool_size 设置得太大(比如超过物理内存的 70%),就可能导致 OOM。

合理的配置:

  • innodb_buffer_pool_size:物理内存的 50%-70%
  • max_connections:根据实际需求设置,不要盲目设大
  • tmp_table_size 和 max_heap_table_size:不要设置过大

情况3:突发流量

有时候内存突然飙升,是因为突发流量。

比如:

  • 某个定时任务突然跑了大量数据
  • 某个接口被恶意刷了
  • 某个查询没有加索引,导致全表扫描

怎么排查?

# 查看 MySQL 的慢查询日志tail -f /var/log/mysql/slow.log# 查看当前正在执行的查询mysql -u root -p -e "SHOW PROCESSLIST;"

05 第五步:制定解决方案

根据根因分析的结果,制定对应的解决方案。

方案1:修复内存泄漏

如果是代码问题导致的内存泄漏:

  • 紧急处理:重启服务,临时缓解
  • 根本解决:找开发修复代码,升级版本

方案2:调整配置

如果是配置不当:

# 编辑 MySQL 配置文件vim /etc/my.cnf# 调整 buffer pool 大小innodb_buffer_pool_size = 4G  # 假设物理内存是 8G# 重启 MySQL 生效systemctl restart mysqld

方案3:优化查询

如果是慢查询导致的内存飙升:

-- 查看慢查询SHOWGLOBAL STATUS LIKE'Slow_queries';-- 开启慢查询日志SETGLOBAL slow_query_log ='ON';SETGLOBAL long_query_time =1;  -- 超过1秒的查询记录为慢查询

然后找开发优化 SQL,加索引,避免全表扫描。

方案4:扩容

如果业务确实在增长,服务器扛不住了:

  • 短期方案:升级配置,加内存
  • 长期方案:做读写分离、分库分表、引入缓存

记住:能用钱解决的问题,都不是问题。关键是你要能证明"确实不够用了",而不是"配置太烂了"。

06 第六步:建立防线,预防再次发生

故障处理完了,但工作还没结束。

1. 设置内存告警

别等 OOM 了才发现问题。设置多级告警:

  • 内存使用率 70%:预警,发个邮件
  • 内存使用率 85%:警告,发个短信
  • 内存使用率 95%:严重,打电话

2. 配置 OOM Score

Linux 允许你为每个进程设置 OOM Score,告诉 OOM Killer 在内存紧张时优先杀哪些进程。

# 查看进程的 OOM Scorecat /proc/12345/oom_score# 调整 OOM Score(-1000 到 1000)echo -1000 > /proc/12345/oom_score_adj  # 降低被杀的概率

关键进程(如数据库)设置负值,非关键进程设置正值。

3. 定期巡检

每天看一眼这些命令的输出:

# 查看内存使用情况free -h# 查看内存占用前10的进程ps aux --sort=-%mem | head -11# 查看 Swap 使用情况swapon --show# 查看内核日志中的 OOM 记录dmesg | grep -i "oom\|killed process"

4. 建立故障知识库

每次故障都记录下来:

  • 现象是什么?
  • 根本原因是什么?
  • 怎么解决的?
  • 怎么预防?

我的经验是:同一个问题,第二次出现时,处理时间能缩短80%。

写在最后

写这篇文章的时候,我又想起了那些凌晨4点被告警电话叫醒的夜晚。

说实话,运维这个工作,很多时候是在"救火"。但每一次救火,都是一次学习的机会。

从手忙脚乱到从容应对,从被动救火到主动预防——这就是成长。

OOM 不可怕,可怕的是不知道为什么会 OOM,不知道怎么预防。

如果你现在正面临 OOM 的问题,别慌,按这篇文章的步骤一步步来。

如果你还没遇到问题,那更好,把这些知识存起来,早晚用得上。

最后送大家一句话:

最好的运维,不是能多快解决故障,而是让故障不发生。

共勉。


你遇到过最棘手的 OOM 故障是什么?是怎么解决的?欢迎留言分享你的实战经验。

最新文章

随机文章