Page Cache是Linux中很重要的一个部分,因此它的难以回收或者容易回收都可能会导致性能问题。
两种误删PC的场景 人为与OS
1.误操作而导致 Page Cache 被回收掉,进而导致业务性能下降明显;
inode
inode是内存中对磁盘文件的索引,进程在查找或者读取文件时就是通过 inode 来进行操作的。
进程查找文件过程
1.进程会通过 inode 来找到文件的地址空间(address_space)
2.结合文件偏移(会转换成 page index)来找具体的 Page。
3.如果该 Page 存在,那就说明文件内容已经被读取到了内存;如果该 Page 不存在那就说明不在内存中,需要到磁盘中去读取。
drop_cache
drop_cache命令可以用于释放inode, 并且我们可以通过写入不同的数值来释放不同类型的 cache(用户数据 Page Cache,内核数据 Slab,或者二者都释放)
谨慎使用drop_cache
在系统内存紧张的时候,运维人员或者开发人员会想要通过 drop_caches 的方式来释放一
些内存,但是由于他们清楚 Page Cache 被释放掉会影响业务性能,所以就期望只去 drop
slab 而不去 drop pagecache。于是很多人这个时候就运行 echo 2 > /proc/sys/vm/drop_caches>
但实际上,当我们执行 echo 2 来 drop slab 的时候,它也会把 Page Cache 给 drop掉,从而导致性能下降。
如何观察是否有人或者有程序执行过 drop_caches
[root@yz117 ~]# grep drop /proc/vmstat
drop_pagecache 0
drop_slab 0
2.内核的一些机制导致业务 Page Cache 被回收,从而引起性能下降。
在内存紧张的时候会触发内存回收,内存回收会尝试去回收 reclaimable(可以被回收的)内存,这部分内存既包含 Page Cache 又包含 reclaimable kernel memory(比如 slab)。
内存回收过程
1.Reclaimer 是指回收者,它可以是内核线程(包括 kswapd)也可以是用户线程。
2.回收的时候,它会依次来扫描 pagecache page 和 slab page 中有哪些可以被回收的.
3.如果有的话就会尝试去回收,如果没有的话就跳过。
4.在扫描可回收 page 的过程中回收者一开始扫描的较少,然后逐渐增加扫描比例直至全部都被扫描完。
relcaim slab过程带来的性能问题 如果 inode 被回收的话,那么它对应的 Page Cache 也都会被回收掉,所以如果业务进程读取 的文件对应的 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 被回收而引起的性能问题?
1.从应用代码层面来优化;
思路是从应用代码层面对PC进行区别对待,重要的PG保护起来,不重要的则随时可以被回收。
比如对于重要的数据,可以通过 mlock(2) 来保护它,防止被回收以及被 drop;对于不重要的数据(比如日志),那可以通过 madvise(2) 告诉内核来立即释放这些 Page Cache。
/* Lock these memory to prevent from being reclaimed */
mlock(p, SIZE);
2.从系统层面来调整。
memory cgroup protection
实际上linux提供了不用修改源码就能实现PC保护的方式,也就是划分水位。
memory.max
这是指 memory cgroup 内的进程最多能够分配的内存,如果不设置的话,就默认不做
内存大小的限制。
memory.high
如果设置了这一项,当 memory cgroup 内进程的内存使用量超过了该值后就会立即被
回收掉,所以这一项的目的是为了尽快的回收掉不活跃的 Page Cache。
memory.low
这一项是用来保护重要数据的,当 memory cgroup 内进程的内存使用量低于了该值
后,在内存紧张触发回收后就会先去回收不属于该 memory cgroup 的 Page Cache,
等到其他的 Page Cache 都被回收掉后再来回收这些 Page Cache。
memory.min
这一项同样是用来保护重要数据的,只不过与 memoy.low 有所不同的是,当 memory
cgroup 内进程的内存使用量低于该值后,即使其他不在该 memory cgroup 内的
Page Cache 都被回收完了也不会去回收这些 Page Cache,可以理解为这是用来保护
最高优先级的数据的。
总结
如果你想要保护你的 Page Cache 不被回收,你就可以考虑将你的业务进程放在一
个 memory cgroup 中,然后设置 memory.{min,low} 来进行保护;与之相反,如果你
想要尽快释放你的 Page Cache,那你可以考虑设置 memory.high 来及时的释放掉不活
跃的 Page Cache。