已归录
故障现象
一台应用主机接收到可用内存比例过低的告警!
故障分析
登录后查看:
# free -m
total used free shared buffers cached
Mem: 15953 15588 364 2 314 1515
-/+ buffers/cache: 13757 2195
Swap: 32767 26 32741
PS:free 表示完全没有使用的内存;shared 表示进程间共享的内存;buffers 表示缓存文件的元数据;cached 表示缓存文件的具体内容。
我们粗略估算一下可用内存:(364+314+1515)/15953 约等于 13%。
那么,到底是谁使用了这么多内存呢?我们使用 top 命令按内存使用率排序:
top - 21:08:46 up 729 days, 2:46, 1 user, load average: 0.00, 0.00, 0.00
Tasks: 217 total, 1 running, 216 sleeping, 0 stopped, 0 zombie
Cpu(s): 0.2%us, 0.3%sy, 0.0%ni, 99.5%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 16335932k total, 15962972k used, 372960k free, 322524k buffers
Swap: 33554428k total, 27276k used, 33527152k free, 1552292k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3554 gdm 20 0 375m 33m 6696 S 0.0 0.2 1114:46 gnome-settings-
2944 root 20 0 7362m 29m 1432 S 0.0 0.2 120:06.07 virt-who
3430 root 20 0 229m 26m 4856 S 0.0 0.2 51:46.62 Xorg
4952 daemon 20 0 2073m 15m 1780 S 0.0 0.1 432:06.61 httpd
8389 daemon 20 0 2073m 15m 1780 S 0.0 0.1 415:41.82 httpd
12648 daemon 20 0 2073m 15m 1884 S 0.0 0.1 375:24.27 httpd
4950 daemon 20 0 2073m 14m 1776 S 0.3 0.1 421:24.36 httpd
3786 daemon 20 0 2073m 14m 1776 S 0.0 0.1 279:46.04 httpd
....
可以看到并没有什么进程有大量的内存消耗。
我们再统计一下所有进程的内存使用总量:
# ps aux | awk '{sum+=$6} END {print sum/1024}'
361.559
可见,所有进程使用的内存只有 360M 左右,那其它内存哪儿去了呢?
既然应用层没有大量的内存使用,那么就应该排查内核空间的使用情况了,最常见的就是观察 slab 了:
# cat /proc/meminfo
......
Slab: 13644596 kB
SReclaimable: 13603636 kB
SUnreclaim: 40960 kB
......
可见,Slab 消耗掉了 13G 的内存空间,且基本上全部是可回收的部分。
Slab 机制专门用于缓存内核的数据对象,主要是用来缓存 Linux 内核中的小对象,比如 inode,dentry,可以提高性能并减少内存碎片。
那到低是什么对象使用了这么多 Slab 空间呢?我们可以使用 slabtop 命令查看或者查看 /proc/slabinfo:
# slabtop --sort=o
Active / Total Objects (% used) : 67450100 / 67692297 (99.6%)
Active / Total Slabs (% used) : 3403998 / 3404005 (100.0%)
Active / Total Caches (% used) : 104 / 182 (57.1%)
Active / Total Size (% used) : 12736934.70K / 12778744.17K (99.7%)
Minimum / Average / Maximum Object : 0.02K / 0.19K / 4096.00K
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
67160160 66963905 99% 0.19K 3358008 20 13432032K dentry
266252 232244 87% 0.10K 7196 37 28784K buffer_head
110608 110585 99% 0.98K 27652 4 110608K ext4_inode_cache
20272 20221 99% 0.03K 181 112 724K size-32
......
# sort -k 2 -n /proc/slabinfo
# name <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>
......
size-32 20173 20272 32 112 1 : tunables 120 60 8 : slabdata 181 181 0
ext4_inode_cache 110609 110612 1000 4 1 : tunables 54 27 8 : slabdata 27653 27653 0
buffer_head 232446 266252 104 37 1 : tunables 120 60 8 : slabdata 7196 7196 0
dentry 66980483 67191180 192 20 1 : tunables 120 60 8 : slabdata 3359559 3359559 0
可见,使用最多的就是 dentry。
dentry 和文件操作相关,一般是应用层频繁的文件操作导致内核频繁申请 dentry 内存所致。
那到底是哪些程序在大量进行文件操作呢?
# lsof | awk '{print $1}' | sort | uniq -c | sort -n
......
96 Xorg
100 gnome-pow
102 gnome-ses
122 metacity
126 master
170 gnome-set
206 gdm-simpl
273 sshd
952 httpd
1249 virt-who
近一步使用 lsof 命令观察具体程序打开了哪些文件进行分析。
解决办法
如果仅仅是 Slab 占用了过多内存,而 SUnreclaim 并不大,且没有持续增长,可以忽略。因为如果有需要,系统会自动释放出内存供其它程序使用。
如果 SUnreclaim 很大且不断增长,很有可能是内核 bug。
SReclaimable 都是 clean 的缓存,随时可以释放,所以也可以手动回收 Slab:
echo 2 > /proc/sys/vm/drop_caches
但是注意,手动清除缓存可能会在一段时间内降低系统性能,所以一般选择在业务低峰时间做。
后续
2020.11.03 22:20 清理后,多长时间又涨起来?
因为 httpd 中的应用已经无法改造,是否是 virt-who 造成的?等下一次问题再现时,在其中一个节点上停用观察之。