drop_cache引发的一个问题

问题:某次共享内存计算key值时,发现文件的inode在变化, 到底是什么原因导致的呢?最后发现是echo 3 > /proc/sys/vm/drop_caches导致的!!

https://time.geekbang.org/column/article/278222?utm_source=related_read&utm_medium=article&utm_term=related_read

根据这篇文章可知:

 

 

也就是确实会释放回收inode内核slab缓存!

  比如说这些 Page Cache 被清理掉后可能会引起系统性能下降。为什么?其实这和 inode 有关,那 inode 是什么意思呢?inode 是内存中对磁盘文件的索引,进程在查找或者读取文件时就是通过 inode 来进行操作的.

 

   如上图所示,进程会通过 inode 来找到文件的地址空间(address_space),然后结合文件偏移(会转换成 page index)来找具体的 Page。如果该 Page 存在,那就说明文件内容已经被读取到了内存;如果该 Page 不存在那就说明不在内存中,需要到磁盘中去读取。你可以理解为 inode 是 Pagecache Page(页缓存的页)的宿主(host),如果 inode 不存在了,那么 PageCache Page 也就不存在了。如果你使用过 drop_cache 来释放 inode 的话,应该会清楚它有几个控制选项,我们可以通过写入不同的数值来释放不同类型的 cache(用户数据 Page Cache,内核数据 Slab,或者二者都释放),这些选项你可以去看Kernel Documentation 的描述。

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

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

 

   Reclaimer 是指回收者,它可以是内核线程(包括 kswapd)也可以是用户线程。回收的时候,它会依次来扫描 pagecache page 和 slab page 中有哪些可以被回收的,如果有的话就会尝试去回收,如果没有的话就跳过。在扫描可回收 page 的过程中回收者一开始扫描的较少,然后逐渐增加扫描比例直至全部都被扫描完。这就是内存回收的大致过程。接下来我所要讲述的案例就发生在“relcaim slab”中,我们从前一个案例已然知道,如果 inode 被回收的话,那么它对应的 Page Cache 也都会被回收掉,所以如果业务进程读取的文件对应的 inode 被回收了,那么该文件所有的 Page Cache 都会被释放掉,这也是容易引起性能问题的地方。

  那这个行为是否有办法观察?这同样也是可以通过 /proc/vmstat 来观察的,/proc/vmstat 简直无所不能

 $ grep inodesteal /proc/vmstat 
 pginodesteal 114341
 kswapd_inodesteal 1291853

  这个行为对应的事件是 inodesteal,就是上面这两个事件,其中 kswapd_inodesteal 是指在 kswapd 回收的过程中,因为回收 inode 而释放的 pagecache page 个数;pginodesteal 是指 kswapd 之外其他线程在回收过程中,因为回收 inode 而释放的 pagecache page 个数。所以在你发现业务的 Page Cache 被释放掉后,你可以通过观察来发现是否因为该事件导致的。

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

  最简单就是不让其回收嘛!!比如说,对于重要的数据,可以通过 mlock(2) 来保护它,防止被回收以及被 drop;对于不重要的数据(比如日志),那可以通过 madvise(2) 告诉内核来立即释放这些 Page Cache。

  Linux 内核同样实现了这种不改应用程序的源码而从系统层面调整来保护重要数据的机制,这个机制就是 memory cgroup protection。它大致的思路是,将需要保护的应用程序使用 memory cgroup 来保护起来,这样该应用程序读写文件过程中所产生的 Page Cache 就会被保护起来不被回收或者最后被回收。memory cgroup protection 大致的原理如下图所示:

 

 

  memory cgroup 提供了几个内存水位控制线 memory.{min, low, high, max} 。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。

   Linux 内核主要是通过 /proc 和 /sys 把系统信息导出给用户,当你不清楚问题发生的原因时,你就可以试着去这几个目录下读取一下系统信息,看看哪些指标异常。比如当你不清楚问题是否由 Page Cache 引起时,你可以试着去把 /proc/vmstat 里面的信息给读取出来,看看哪些指标单位时间内变化较大。如果 pgscan 相关指标变化较大,那就可能是 Page Cache 引起的,因为 pgscan 代表了 Page Cache 的内存回收行为,它变化较大往往意味着系统内存压力很紧张。/proc 和 /sys 里面的信息可以给我们指出一个问题分析的大致方向,我们可以判断出问题是不是由 Page Cache 引起的,但是如果想要深入地分析问题,知道 Page Cache 是如何引起问题的,我们还需要掌握更加专业的分析手段,专业的分析工具有 ftrace,ebpf,perf 等。

 

 

 

 我们继续以内存规整 (memory compaction) 为例,来看下如何利用 tracepoint 来对它进行观察:

#首先来使能compcation相关的一些tracepoing
$ echo 1 >
/sys/kernel/debug/tracing/events/compaction/mm_compaction_begin/enable
$ echo 1 >
/sys/kernel/debug/tracing/events/compaction/mm_compaction_end/enable 

#然后来读取信息,当compaction事件触发后就会有信息输出
$ cat /sys/kernel/debug/tracing/trace_pipe
           <...>-49355 [037] .... 1578020.975159: mm_compaction_begin: 
zone_start=0x2080000 migrate_pfn=0x2080000 free_pfn=0x3fe5800 
zone_end=0x4080000, mode=async
           <...>-49355 [037] .N.. 1578020.992136: mm_compaction_end: 
zone_start=0x2080000 migrate_pfn=0x208f420 free_pfn=0x3f4b720 
zone_end=0x4080000, mode=async status=contended

从这个例子中的信息里,我们可以看到是 49355 这个进程触发了 compaction,begin 和 end 这两个 tracepoint 触发的时间戳相减,就可以得到 compaction 给业务带来的延迟,我们可以计算出这一次的延迟为 17ms。

  很多时候由于采集的信息量太大,我们往往需要借助一些自动化分析的工具来分析,这样会很高效。比如之前写过一个perf script来分析直接内存回收对业务造成的延迟。另外你也可以参考 Brendan Gregg 基于 bcc(eBPF) 写的direct reclaim snoop来观察进程因为 direct reclaim 而导致的延迟。

https://lore.kernel.org/linux-mm/_/text/help/  这几个网址比较有用

  PS:tmpfs 作为一种特殊的 Shmem,它消耗的内存是不会体现在进程内存中的,这往往会给问题排查带来一些难度。要想高效地分析这种类型的问题,你必须要去熟悉系统中的内存类型。除了 tmpfs 之外,其他一些类型的内存也不会体现在进程内存中,比如内核消耗的内存:/proc/meminfo 中的 Slab(高速缓存)、KernelStack(内核栈)和 VmallocUsed(内核通过 vmalloc 申请的内存),这些也是你在不清楚内存被谁占用时需要去排查的

 

看了这篇文章我们在回到正题!!

即使回收了inode 但是我重新打开使用inode 不应该变化啊?

目前使用了aufs文件系统只能去看aufs系统会不会导致这个问题了!!!!!

先说结论是:根据mount查看使用noxino 参数挂载, 会导致inode 变化

当然这是通过google搜索出来的!!但是怎样通过分析源码快速找出这个问题呢?

 

posted @ 2022-04-07 15:00  codestacklinuxer  阅读(127)  评论(0编辑  收藏  举报