earlyoom预防机器卡死

背景

机器还没来得及oom,机器就出现挂死的状态,swap无法交换出,或者直接挂死

这个问题比较好复现
在机器上面一直进行内存的申请即可

1
python3 memory.py 100 40000

这个在x86上面做测试的时候,系统能够比较快的oom,但是这个板卡的系统盘本身慢,这个就可能出现卡顿的情况了

系统的oom,需要进行一些计算和系统处理,并且有个问题是,很多进程都不杀,因为都是系统进程,很多是-1000

优先级又很低,oom并不能释放太多内存,无法及时释放内存就会卡死机器了

参数调整

1
vm.min_free_kbytes=512144

这个我们采用512MB来作为系统的保证内存,这个是oom的判断条件,默认的16MB太小了,并不足以保证运行的环境,这个后面可以根据实际情况再调整
其它参数维持系统之前的参数(系统上面看到是这个)

1
vm.overcommit_memory = 1

这个0是默认的,1就是无限分配内存,这个压测更极端的情况

earlyoom配置参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
root@myserver:~# cat /etc/default/earlyoom
# Default settings for earlyoom. This file is sourced by /bin/sh from
# /etc/init.d/earlyoom.

# Options to pass to earlyoom
EARLYOOM_ARGS=""

# Examples:

# Available minimum memory 5%
# EARLYOOM_ARGS="-m 5"

# Available minimum memory 15% and free minimum swap 5%
EARLYOOM_ARGS="-m 5 -s 4"

# Use kernel oom killer
# EARLYOOM_ARGS="-k"

# See more at `earlyoom -h'

其中的-m 5 -s 4
是物理内存5% swap %4
对应到794 MiB
swap剩余327 MiB
这个就是杀进程的判断点,系统剩余多少内存的时候介入,这两个加起来是1G左右,操作系统的判断的时候没有区分swap和物理内存,这个地方会更精细,这个设置的可以后面再调整更小,也可以根据系统需要的内存来看,这个总共留1G也不算太大

下面可以看到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
root@myserver:~# systemctl status earlyoom
● earlyoom.service - Early OOM Daemon
Loaded: loaded (/lib/systemd/system/earlyoom.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2024-11-14 14:56:57 +08; 2s ago
Docs: https://github.com/rfjakob/earlyoom
Main PID: 41953 (earlyoom)
Tasks: 1 (limit: 9830)
Memory: 1.0M
CGroup: /system.slice/earlyoom.service
└─41953 /usr/bin/earlyoom -m 5 -s 4

11月 14 14:56:57 myserver earlyoom[41953]: earlyoom v0.12
11月 14 14:56:57 myserver earlyoom[41953]: mem total: 15895 MiB, min: 794 MiB (5 %)
11月 14 14:56:57 myserver earlyoom[41953]: swap total: 8191 MiB, min: 327 MiB (4 %)

运行效果可以看到,实际物理内存已经基本耗尽了,但是系统自带的oom并没有触发,我们用的这个earlyoom也会有一点滞后,但是并没卡死系统

总结

1、调整下系统最小保留内存
2、设置earlyoom避免内存耗尽
3、板卡的内存耗尽到oom之间应该存在滞后,这个early可以避免没来得及oom的情况

验证大内存压力情况下的稳定性
剩余的内存的地方可以根据实际情况进行调整,上面是预估的保留内存(可以测试验证看下情况)

附录

占用内存脚本 memory.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#! /usr/bin/python3
import time
import sys

def allocate_memory(allocation_size_mb, total_memory_mb):
# 将 MB 转换为字节
allocation_size_bytes = allocation_size_mb * 1024 * 1024
total_memory_bytes = total_memory_mb * 1024 * 1024

# 初始化用于存储分配数据的列表
allocated_memory = []

# 追踪已分配的总内存量
allocated_total = 0

try:
while allocated_total < total_memory_bytes:
# 每次分配内存
allocated_memory.append(bytearray(allocation_size_bytes))
allocated_total += allocation_size_bytes
print(f"Allocated: {allocated_total / (1024 ** 2):.2f} MB")
time.sleep(0.5) # 使内存增长速度更缓慢,便于观察
except MemoryError:
print("Memory allocation failed. The system ran out of memory.")

print("Memory allocation complete. Holding memory...")

# 无限循环,保持进程不退出
while True:
time.sleep(1)

if __name__ == "__main__":
# 获取命令行参数
if len(sys.argv) != 3:
print("Usage: python script.py <allocation_size_mb> <total_memory_mb>")
sys.exit(1)

# 解析参数
allocation_size_mb = int(sys.argv[1])
total_memory_mb = int(sys.argv[2])

# 调用内存分配函数
allocate_memory(allocation_size_mb, total_memory_mb)