如何为Ubuntu 22.04中system.slice下的自定义系统服务启用systemd-oomd以实现内存超限自动OOM杀死并重启
我完全懂你的闹心——升级到22.04后,原来靠MemoryMax之类的参数让服务超内存就被杀死重启的机制突然失效,反而变成进程挂起僵住,这换谁都头疼。咱们一步步把熟悉的旧行为找回来,同时适配systemd-oomd的新逻辑:
首先得理清核心问题:systemd-oomd默认只盯着user.slice下的用户服务,你的fail2ban.service在system.slice系统服务容器里,所以它根本没被oomd纳入监控;另外现在MemoryMax的逻辑变了,只会把进程卡进内存受限状态,不会直接触发OOM杀进程,得让oomd来接手这个“执法”的活。
第一步:确保服务被杀死后能自动重启
先确认你的服务单元有自动重启的配置——如果没有,先加个drop-in文件补全:
创建/etc/systemd/system/fail2ban.service.d/restart.conf,内容如下:
[Service] Restart=on-failure RestartSec=5s
这个配置会让服务在失败(包括被OOM杀死)后5秒自动重启,和你之前的需求匹配。
第二步:让systemd-oomd盯上你的服务
编辑/etc/systemd/oomd.conf,找到[OOM]区块,添加一行指定要监控的目标服务:
[OOM] SwapUsedLimit=50% DefaultMemoryPressureLimit=10% DefaultMemoryPressureDuration=5s MonitoredUnits=fail2ban.service
如果你想让oomd监控所有system.slice下的系统服务,把MonitoredUnits=fail2ban.service改成MonitoredUnits=system.slice就行。
改完后重启systemd-oomd让配置生效:
systemctl daemon-reload && systemctl restart systemd-oomd
第三步:验证监控是否生效
运行oomctl命令,现在你应该能在Memory Pressure Monitored CGroups列表里看到/system.slice/fail2ban.service的条目了,这说明oomd已经开始盯着它的内存状态了。
第四步:(可选)自定义内存压力触发阈值
默认的10%内存压力(即进程等待内存的时间占比)+5秒持续时间可能不符合你的实际场景,可以给服务单独设置更贴合的阈值:
创建/etc/systemd/system/fail2ban.service.d/oom-pressure.conf:
[Service] MemoryPressureLimit=20% MemoryPressureDuration=10s
这个配置表示,当服务的内存压力持续10秒超过20%时,oomd就会出手杀掉它。
顺便给你掰扯下slice和scope的区别
你完全不用纠结要不要新建slice或者scope,简单说:
.slice是cgroup的层级容器,用来归类服务,比如system.slice专门装系统服务,user.slice装用户会话服务;.scope一般是临时进程组,比如用systemd-run临时启动的进程会放在scope里,你的常驻系统服务用.service就够了,完全不需要动slice或者scope。
为什么原来的MemoryMax会让进程挂起?
升级后,systemd和oomd的交互逻辑变了:原来MemoryMax会直接触发内核OOM杀进程,现在它只会把进程限制在内存上限内,进程会进入阻塞状态等待内存释放,而oomd是通过内存压力(进程等待内存的时间比例)来判断是否需要杀进程,这种机制更智能,能避免误杀,但需要我们手动把服务加入监控列表才行。
现在你的服务应该能回到“内存超限被杀死→自动重启”的熟悉状态了,试试看!
备注:内容来源于stack exchange,提问作者ulidtko

