1.问题起源
有一批虚拟机都是4C8G规格的,上面都运行着数据库或者mq,kafka等程序,偶尔会出现个别组件失联的情况,使用SSH登录的时候异常的慢,即便登录进去了一条命令也得卡十几秒才能执行完,使用top查看时发现有一个叫kswapd0的进程占用了大量CPU资源,而且磁盘等待(wa)特别高。
从上图中可以看到,cpu总占用率在40%左右,磁盘等待在43%上下浮动,cpu的大量的时间都在等待磁盘完成IO操作,可见有程序在频繁的请求IO,而下面光是kswapd0一个进程就吃满了一个核心,pid还是如此靠前的41,由此可见这是一个系统级进程。
2.虚心求教
我查阅了大量资料,发现该程序来源于虚拟内存,是系统常驻进程,专门负责内存换页,cpu会定时唤醒该进程检查内存使用情况,当内存中的空闲页低于pages_low的时候,该进程会扫描内存,将长久不用的内存数据转移到磁盘空间上,待程序需要使用这部分时再将其搬回物理内存供程序使用,他每次会在物理内存中清理32个free内存页,一直清理直到free内存页的数量大于pages_high的时候停止。这两个参数都是内核参数,目前没看到可以在哪里设置这两个参数。
有文章说pages_low、pages_high的值是在函数void setup_per_zone_pages_min(void)中进行设置的,这个函数位于mm\page_alloc.c之中。(这段话我看懂了,但是我找不到这个函数,因为我不会看linux源码,对c的了解也只是一点点)
总之我们可以看出一点,如果物理内存不足,系统就会陷入调用kswapd0来换页清理内存但内存不足导致一直清理不出能达到pages_high页数的内存页进而一直清理内存的困境。也正是如此才导致磁盘IO与CPU居高不下。
3.问题查明
所以其实问题原因在于内存不足,但我使用free命令排查了内存之后发现问题更诡异了起来。
明明显示还有4.8G内存,为什么还是会出现kswapd0进程呢?明明还有4.8G内存,为什么可用内存只剩可怜的几百KB了呢?
此时我灵光一现,想到去排查系统参数,果不其然让我发现了一个很关键的参数
vm.min_free_kbytes
。该参数表示linux系统最低会保留多少空闲内存,当可用内存小于这个参数时,系统会触发cache回收内存,同样包括触发kswapd0程序进行内存换页。该参数的单位是KB。
这个参数在这台8G内存的虚拟机上配置是4096000,高达3.9G。
所以free内存虽然显示4.8G,但这个4.8G中有3.9G是系统保留的,不允许使用的,真正可用的内存只剩几百MB,系统自然会开始回收内存。
官方建议是这个配置项的值在物理内存的0.4%~5%之间,对于总物理内存低于32G的机器来说,不建议配置此项,默认值即可。
4.额外的内容
vm.min_free_kbytes所保留的内存会在可用的物理内存被占满之后让系统运行MMU(内存管理单元)用的,好让系统可以清理内存,如果设置的过小,比如小于4096,那么系统则很容易崩溃,因为这会导致MMU无法运行。
该选项的默认值是45056,也就是45M。