在我之前的文章中有粉丝提到内存不足,需要频繁清理系统缓存的问题,今天我们就来聊聊Page Cache相关的一系列问题。
在Linux上直接查看Page Cache的方式有很多,包括free 、/proc/vmstat 命令等,它们的内容其实是一致的,这些性能查询工具的数据来源都是/proc/meminfo,今天我们就用最常用的 free 命令的输出解释下。
free命令输出
meminfo信息
我们观察free命令的输出,在结合/proc/meminfo的结果,你可以发现 buff/cache 包括下面这几项:
buff/cache = Buffers + Cached + SReclaimable。
从这个公式中,你能看到 free 命令中的 buff/cache 是由 Buffers、Cached 和 SReclaimable 这三项组成的,它强调的是内存的可回收性,也就是说,可以被回收的内存会统计在这一项。关于buff/cache的介绍,我在前面的文章中有详细讲过。这里的SReclaimable是指可以被回收的内核内存,包括 dentry 和 inode 等。
如果你的业务对Page Cache比较敏感,比如说你的业务数据对延迟很敏感,或者再具体一点,你的业务指标对TP99(99 分位)要求较高,这种场景下,如果对Page Cache操作不当会产生的问题。
我们知道,对于Page Cache而言,是可以通过drop_cache来清掉的,很多人在看到系统中存在非常多的Page Cache时会习惯使用drop_cache来清理它们。
于是这样就引入了一个容易被我们忽略的问题:当我们执行 echo 2 来 drop slab 的时候,它也会把 Page Cache 给 drop 掉,业务性能产生了明显的下降。
在内存紧张的时候会触发内存回收,内存回收会尝试去回收 reclaimable(可以被回收的)内存,这部分内存既包含 Page Cache 又包含 reclaimable kernel memory(比如 slab),我们可以通过/proc/vmstat 来观察的内核回收的事件。
grep inodesteal /proc/vmstat
vmstat信息
这个行为对应的事件是 inodesteal,就是上面这两个事件,其中:
从应用程序代码层面来解决是相对比较彻底的方案,因为应用更清楚哪些 Page Cache 是重要的,哪些是不重要的,所以就可以明确地来对读写文件过程中产生的 Page Cache 区别对待。例如:
在有些情况下,对应用程序而言,修改源码是件比较麻烦的事,如果可以不修改源码来达到目的那就最好不过了。Linux 内核同样实现了这种不改应用程序的源码而从系统层面调整来保护重要数据的机制,这个机制就是 memory cgroup,它提供了几个内存水位控制线 memory.{min, low, high, max}。
如果你想要保护你的Page Cache不被回收,你就可以考虑将你的业务进程放在一个memory cgroup中,然后设置 memory.{min,low} 来进行保护;与之相反,如果你想要尽快释放你的Page Cache,那你可以考虑设置memory.high 来及时的释放掉不活跃的Page Cache。