在IDC运维工作中,Linux服务器因内存耗尽触发OOM(Out of Memory)杀手是常见的线上故障。这类问题往往具有突发性,如果处理不及时可能导致核心服务中断。本文结合实战经验,分享一套完整的OOM问题排查和优化方案。

问题排查三板斧

首先是快速定位OOM事件。系统日志是第一手资料,执行dmesg | grep -i oom-killer可以直接看到OOM触发的时间、被杀掉的进程以及当时的内存分配情况。重点关注Out of memory: Killed process这一行后面的进程名和PID,这通常是内存泄漏的元凶,但也可能只是"背锅侠"——真正吃内存的进程可能更早启动。

其次是还原内存快照。很多运维人员只看free -h,但free显示的是当前状态,OOM发生时的状态才是关键。建议用/proc/buddyinfo查看内存碎片情况,用/proc/pid/smaps分析具体进程的内存分布,特别是Anonymous内存和Swap占用。ps aux --sort=-%mem | head -10可以快速列出内存占用前10的进程。

最后是验证系统配置。检查sysctl vm.overcommit_memory的值,默认0是启发式分配,1是允许超售,2是严格不超售。对于数据库这类关键服务,建议设为2,同时调整vm.overcommit_ratio到合适值(物理内存的50%-80%)。

实战优化策略

第一,配置OOM得分调整。不想让核心服务被随机杀掉,可以在启动脚本中设置:echo -1000 > /proc/$(pidof mysqld)/oom_score_adj。数值越低越不容易被杀,-1000是绝对保护。

第二,开启Swap但限制使用。很多人迷信"关闭Swap性能更好",但在IDC环境中,Swap是内存的安全垫。建议配置vm.swappiness=10,让系统只在内存真紧张时才用Swap,同时监控/proc/swaps的使用量,Swap使用率超过30%就该扩容了。

第三,定期内存回收。用echo 3 > /proc/sys/vm/drop_caches可以回收页缓存、目录项和inode,但这是应急手段不是日常操作。日常应该用systemd-run定期执行内存碎片整理,或者配置ksm服务合并相同内存页。

预防大于治理

建立内存监控基线是根本。用Prometheus+Grafana监控node_memory_Active_bytesnode_memory_Inactive_bytesnode_memory_SwapFree_bytes这三个指标,设置70%、85%两级告警。OOM发生前通常会有10-30分钟的内存爬升期,这个窗口足够运维人员介入处理。

总结:OOM问题不是简单的"内存不够加内存",而是系统级的资源管理问题。从日志定位、进程分析、系统调优到监控预警,每一步都做扎实,才能把故障消灭在萌芽状态。