Linux服务器内存管理直接关系到服务稳定性。当系统可用内存耗尽时,OOM Killer会强制杀死进程以保护内核运行,生产环境常出现关键服务被误杀的问题。理解OOM Killer触发机制并配合cgroups做内存限制,是服务器运维中保障核心服务可用性的关键技能。
OOM Killer触发机制与评分规则
Linux内核在分配内存时采用超额承诺策略,物理内存不足时触发OOM Killer。OOM Killer通过oom_score对每个进程评分,选择分数最高的进程杀死。评分依据包括:内存占用大小、运行时间、nice值、是否为root用户、是否为内核线程等。
查看各进程OOM评分:
# 查看所有进程的oom_score
for pid in $(ls /proc | grep -E '^[0-9]+$'); do
score=$(cat /proc/$pid/oom_score 2>/dev/null)
name=$(cat /proc/$pid/comm 2>/dev/null)
echo "$score $pid $name"
done | sort -rn | head -20
# 查看进程详细oom_score_adj
cat /proc/$(pidof nginx)/oom_score_adj
oom_score_adj取值范围-1000到1000,值越大越容易被杀。设为-1000表示禁止OOM Killer杀死该进程,设为1000表示优先杀死。保护关键服务的配置:
# 保护Nginx主进程不被OOM杀死
echo -1000 > /proc/$(pidof nginx)/oom_score_adj
# 持久化配置,写入systemd service文件
# /etc/systemd/system/nginx.service
[Service]
OOMScoreAdjust=-1000
cgroups v2内存限制与隔离配置
cgroups v2将CPU、内存、IO等子系统统一到层级结构中,配置更简洁。通过cgroups限制容器或进程组的内存使用,防止单个服务耗尽系统内存导致全局OOM。
创建cgroup并设置内存限制:
# 启用cgroups v2
mount | grep cgroup2
# /sys/fs/cgroup type cgroup2 ...
# 创建应用cgroup
mkdir /sys/fs/cgroup/app_web
echo $$ > /sys/fs/cgroup/app_web/cgroup.procs
# 设置内存上限为4GB
echo 4294967296 > /sys/fs/cgroup/app_web/memory.max
# 设置内存软限幅为3GB,超过后优先回收
echo 3221225472 > /sys/fs/cgroup/app_web/memory.high
# 设置swap上限(v2中swap计入memory.max,可通过memory.swap.max单独限制)
echo 2147483648 > /sys/fs/cgroup/app_web/memory.swap.max
# 查看内存使用情况
cat /sys/fs/cgroup/app_web/memory.current
cat /sys/fs/cgroup/app_web/memory.events
memory.max设置硬上限,超出时触发cgroup内OOM Killer,只杀该cgroup内的进程;memory.high设置软上限,超出后内核优先回收该cgroup的内存页面,不直接杀进程。
systemd集成cgroups内存限制
生产环境通常通过systemd管理服务,systemd原生支持cgroups v2资源配置:
# /etc/systemd/system/webapp.service
[Service]
ExecStart=/usr/bin/python3 /opt/app/main.py
MemoryMax=4G
MemoryHigh=3G
MemorySwapMax=2G
MemoryDenyWriteExecute=yes
# CPU限制补充
CPUQuota=200%
CPUWeight=500
# IO限制补充
IOWeight=500
IOReadBandwidthMax=/dev/sda 50M
重载配置并重启服务:
systemctl daemon-reload
systemctl restart webapp
# 验证cgroup配置
systemctl show webapp -p MemoryMax -p MemoryHigh
systemd-cgls webapp
内存问题排查实战流程
当服务器发生OOM事件时,排查步骤:
# 1. 查看OOM Killer日志
dmesg | grep -i "killed process"
journalctl -k | grep -i oom
# 2. 查看被杀进程详情
dmesg -T | grep "Out of memory"
# 3. 使用smem查看进程实际内存占用(含PSS/USS)
smem -rs pss | head -20
# 4. 使用pidstat实时监控
pidstat -r 5
# 5. 抓取内存快照分析
# 在OOM触发前设置earlyoom或kernel panic dump
# /etc/sysctl.d/99-oom.conf
vm.panic_on_oom=0
vm.overcommit_memory=1
vm.overcommit_ratio=80
vm.overcommit_memory=1允许内核超额分配内存,配合cgroups做精确限制;vm.overcommit_ratio=80限制超额比例。earlyoom作为用户态OOM守护进程,可在内核OOM之前主动干预:
# 安装earlyoom
apt install -y earlyoom
# 配置:内存低于10%且swap低于10%时触发
# /etc/default/earlyoom
EARLYOOM_ARGS="-r 3600 -m 10 -s 10 --prefer '(java|python)' --avoid '(sshd|nginx|systemd)'"
systemctl enable --now earlyoom
通过OOM评分保护、cgroups内存隔离、earlyoom预干预三层机制,可以将内存耗尽时的影响范围控制在非关键服务内,避免关键进程被误杀导致服务不可用。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/linux-fu-wu-qi-nei-cun-guan-li-shi-zhan-oomkiller-chu-fa-ji/