iftop 跑满 CPU

故事的开始

某天一位系统大佬忙不过来了,拜托另一位大佬丢了个在 NC 上抓的 dump 让我帮忙看下,现象很简单,执行 iftop 时要过好几分钟才返回,同时 CPU 跑满。

故事的进展

拿到 dump 先把对应的符号装上去,然后用 crash 跑起来,先看看输出了什么。
iftop 跑满 CPU
除了能看到 iftop 正在运行之外,好像也没什么有用的信息。

既然当前运行的进程刚好是 iftop,顺便看下调用栈
iftop 跑满 CPU
看到这么长的调用栈,一般都是有故事的。这个进程在执行某个动作的时候触发了缺页异常,然后在尝试回收内存页。

在 Linux 的内存管理中,有一个内核进程 kswapd 会在特定情况下默默回收最近最少使用(LRU)的内存页,它回收的机制是这样的:当空闲的内存页低于 page_low 时,内核就会唤醒该进程,然后它会从 LRU 的内存页中回收进程直到内存页达到 page_high,由于存在 kswapd 主动回收内存的机制,一般来说,进程不会自己去做内存回收,只有在 kswapd 回收的内存也不能满足进程的内存需求的时候进程才会自己去回收内存,出现这种现象有可能是 page_low 设置得太低了,导致唤醒 kswapd 的时候系统的空闲内存已经很少了,这种情况可以适当调大系统参数 vm.extra_free_kbytes。这里多说一句,还有个参数是 pages_min,代表保留内存页的数目,一般 pages_low 总是被设置为 pages_min 的 5/4,而 pages_high 总是被设置成 pages_min 的 3/2。而进程在自己回收内存的时候,做的动作时 direct reclaim,direct reclaim 的机制是不会区分 dirty 的内存页和 clean 的内存页,如果遇到 dirty 的内存页会先把该内存页写回磁盘上再回收,因此,direct reclaim 比较消耗性能。

如果是这种情况,这个时候系统空闲的内存应该很少了,然鹅...
iftop 跑满 CPU
可以看到空闲内存还有一半以上,那就说明不是这个问题啊。

继续查询翻阅各种资料后,发现有个参数 vm.zone_reclaim_mode 控制着进程是否会在其它的 Zone 里回收内存,当这个参数非 0 时,即使别的 Zone 里有很多空闲内存,进程宁愿自己回收内存也不会到别的 Zone 中去申请内存。如果是这种情况,确实会出现 free 的内存还很多但是进程还会自己去做 direct reclaim 来回收内存的情况。会不会是这个参数的问题呢?改完之后效果立竿见影,iftop 很快就能返回且不再跑满 CPU 了!