问题场景:
今天早上收到报警,系统剩余内存低于15%;这台机器运行的服务为nginx,理论上占用的内存不会很多,于是进行排查;
查看使用的内存:free -m
查看活跃进程使用的内存:ps aux --sort -rss | head
可以看到free -m使用的内存与前10个活跃进程使用的内存存在较在差距~
问题分析及解决:
通过查阅资料,有可能是slab占用了内存;
步骤一:安装atop工具,查看内存的具体使用情况
yum install atop -y
执行命令:atop
可以看到slab占用了2.6G的内存,确定了引用内存异常的原因是slab
步骤二:查看slab占用内存的具体情况
执行命令:cat /proc/meminfo | awk '{sum=$2/1024} {print $1 sum " MB"}' | grep claim
SReclaimable:3153.37 MB SUnreclaim:25.0664 MB
SReclaminable:表示可回收的slab占用的内存
SUnreclaim:表示不可回收的slab占用的内存
由此猜想,slab可回收的内存可以由系统进行自动回收或者手动回收
步骤三:查看具体是什么占用了slab内存
执行命令:slabtop
注:可以看到是dentry占用大部分的slab内存
slab内存分类:
dentry:目录项缓存
inode_cache:vfs索引节点缓存
slab是Linux操作系统的一种内存分配机制。其工作是针对一些经常分配并释放的对象,您可以看看哪些应用进程的slab占用的内存比较多,是否这些应用需要频繁的请求和释放内存,比如进行一些小文件的读写。如果都是应用的正常使用,可以考虑升级服务器内存,如果内存不足影响业务,需要临时释放一下slab占用的内存;
slab内存的释放策略:
相关内核参数:vm.drop_caches
参数值含义:
0:不做任何处理,由系统自己管理
1:清空pagecache(页缓存)
2:清空dentry和inode_cache(目录荐和索引节点缓存)
3:清空pagecache、dentries和inode_cache
步骤四:手动回收slab中的可回收内存
#将内存的数据同步到磁盘
sync
#手动清空页缓存(pagecache)和元数据缓存(slab)
sudo sysctl -w vm.drop_caches=3 或者 echo 3 > /proc/sys/vm/drop_caches
#内存回收后把内核参数改为原来的值
sudo sysctl -w vm.drop_caches=0 或者 echo 0 > /proc/sys/vm/drop_caches
注:以上修改的方式是临时生效
相关内核参数:kswapd0
kswapd0:专门的内核线程用来定期回收内存;
为了衡量内存的使用情况,kswapd0定义了三个内存阈值(watermark,也称为水位),分别是:
页最小阈值(pages_min)
页低阈值(pages_low)
页高阈值(pages_high)
关系图:
kswapd0定期扫描内存的使用情况,并根据剩余内存落在这三个阈值的空间位置,进行内存的回收操作。
剩余内存小于页最小阈值,说明进程可用内存都耗尽了,只有内核才可以分配内存。
剩余内存落在页最小阈值和页低阈值中间,说明内存压力比较大,剩余内存不多了。这时kswapd0会执行内存回收,直到剩余内存大于高阈值为止。
剩余内存落在页低阈值和页高阈值中间,说明内存有一定压力,但还可以满足新内存请求。
剩余内存大于页高阈值,说明剩余内存比较多,没有内存压力。
vm.min_free_kbytes:保留给内核使用的;当到达min,系统会启动 kswapd0 进行内存回收;此参数的默认值为67584;
可以通过此参数来的值让系统自动回收slab,但是此参数不宜设置过大;
由此此参数引发的血案:
生产中某台机器调高了此参数为1G,当系统free的内存小于1GB时,观察到kswapd进程开始工作(进程状态从Sleeping变为Running),同时dentry_cache开始被系统回收,直到系统free的内存介于low阈值和high阈值之间,停止回收。
如果系统的free内存一直低于1G,则kswapd0一直运行,造成系统持续较大压力!