大致可以分为两方面:

  • 误操作而导致 Page Cache 被回收掉,进而导致业务性能下降明显;
  • 内核的一些机制导致业务 Page Cache 被回收,从而引起性能下降。

对 Page Cache 操作不当产生的业务性能下降

inode 是内存中对磁盘文件的索引,进程在查找或者读取文件时就是通过 inode 来进行操作的,我们用下面这张图来表示一下这种关系:

image.png

通过写入不同的数值来释放不同类型的 cache:

  • 当我们执行 echo 2 来 drop slab 的时候,它也会把 Page Cache 给 drop 掉

image.png

通过 /proc/vmstat 来判断是否有执行过 drop_caches:

  1. $ grep drop /proc/vmstat
  2. drop_pagecache 3
  3. drop_slab 2

如上所示,它们分别意味着 pagecache 被 drop 了 3 次(通过 echo 1 或者 echo 3),slab 被 drop 了 2 次(通过 echo 2 或者 echo 3)。如果这两个值在问题发生前后没有变化,那就可以排除是有人执行了 drop_caches;否则可以认为是因为 drop_caches 引起的 Page Cache 被回收。

内核机制引起 Page Cache 被回收而产生的业务性能下降

在内存紧张的时候会触发内存回收,内存回收会尝试回收 reclaimable(可以被回收的)内存,这部分内存既包含 Page Cache 又包含 reclaimable kernel memory (比如 slab)。我们可以用下图来简单描述这个过程:

image.png

如果 inode 被回收的话,那么它对应的 Page Cache 也都会被回收掉:

 $ grep inodesteal /proc/vmstat 
 pginodesteal 114341
 kswapd_inodesteal 1291853
  • kswapd_inodesteal 是指在 kswapd 回收的过程中,因为回收 inode 而释放的 pagecache page 个数;
  • pginodesteal 是指 kswapd 之外其他线程在回收过程中,因为回收 inode 而释放的 pagecache page 个数。

如何避免 Page Cache 被回收而引起的性能问题?

避免 Page Cache 里相对比较重要的数据被回收掉的思路也是有两种:

  • 从应用代码层面来优化;
  • 从系统层面来调整。

从应用程序代码层面来解决是相对比较彻底的方案,因为应用更清楚哪些 Page Cache 是重要的,哪些是不重要的,所以就可以明确地来对读写文件过程中产生的 Page Cache 区别对待。比如说,对于重要的数据,可以通过 mlock(2) 来保护它,防止被回收以及被 drop;对于不重要的数据(比如日志),那可以通过 madvise(2) 告诉内核来立即释放这些 Page Cache。

Linux 内核同样实现了这种不改应用程序的源码而从系统层面调整来保护重要数据的机制,这个机制就是 memory cgroup protection。

image.png