运维开发网

1-3.处理Page Cache难以回收产生load飙高问题

运维开发网 https://www.qedev.com 2020-09-20 12:11 出处:51CTO 作者:hanson世纪
一、现象及原因在日常工作中,应该会遇到这种情形:系统卡顿、敲命令响应非常慢、业务抖动厉害,伴随着系统load飙高。原因可能有:直接内存回收引起的load飙高;系统中脏页积压过多引起的load飙高;系统NUMA策略配置不当引起的load飙高。二、直接内存回收引起load飙高或者业务时延抖动直接内存回收直接内存回收:指在进程上下文同步进行内存回收。直接内存回收怎么引起load飙高?直接内存回收时在进程

一、现象及原因

在日常工作中,应该会遇到这种情形:系统卡顿、敲命令响应非常慢、业务抖动厉害,伴随着系统load飙高。

  • 原因可能有:
    • 直接内存回收引起的load飙高;
    • 系统中脏页积压过多引起的load飙高;
    • 系统NUMA策略配置不当引起的load飙高。

二、直接内存回收引起 load 飙高或者业务时延抖动

直接内存回收

  1. 直接内存回收:指在进程上下文同步进行内存回收。
  2. 直接内存回收怎么引起load飙高?
    • 直接内存回收时在进程申请内存的过程中同步进行的回收,而回收过程可能会消耗很多时间,进而导致进程的后续行为被迫等待,从而造成很长时间的延迟,以及系统CPU利用率升高,最终load飙高。
  3. 内存回收过程

    1-3.处理Page Cache难以回收产生load飙高问题

    • 上图可以看到,在开始内存回收后,首先进行后台异步回收(上图中蓝色标记的地方),这不会引起进程的延迟;如果后台异步回收跟不上进程内存申请的速度,就会开始同步阻塞回收,导致延迟(上图中红色和粉色标记的地方,这就是引起 load 高的地址)。
  4. 针对直接内存回收引起load飙高或者业务RT抖动的问题,一个解决方案就是及早地触发后台回收来避免应用程序进行直接内存回收

后台内存回收

  1. 后台回收原理示意图

    1-3.处理Page Cache难以回收产生load飙高问题

    • 当内存水位低于 watermark low 时,就会唤醒 kswapd 进行后台回收,然后 kswapd 会一直回收到 watermark high。
    • 可以增大 min_free_kbytes 这个配置选项来及早地触发后台回收,该选项最终控制的是内存回收水位。

      vm.min_free_kbytes = 4194304

    • 对于大于等于 128G 的系统而言,将 min_free_kbytes 设置为 4G 比较合理(经验值),既不造成较多的内存浪费,又能避免掉绝大多数的直接内存回收。
    • 该值的设置和总的物理内存并没有一个严格对应的关系,如果配置不当会引起一些副作用,所以在调整该值之前,建议:渐进式地增大该值,比如先调整为 1G,观察 sar -B 中 pgscand 是否还有不为 0 的情况;如果存在不为 0 的情况,继续增加到 2G,再次观察是否还有不为 0 的情况来决定是否增大,以此类推。

      注意:即使将该值增加得很大,还是可能存在 pgscand 不为 0 的情况,这时候需要考虑,业务是否可以容忍,如果可以容忍那就没有必要继续增加了,也就是说,增大该值并不是完全避免直接内存回收,而是尽量将直接内存回收行为控制在业务可以容忍的范围内。这个方法可以用在 3.10.0 以后的内核上(对应的操作系统为 CentOS-7 以及之后更新的操作系统)。

  2. 存在缺陷
    • 提高了内存水位后,应用程序可以直接使用的内存量就会减少,这在一定程度上浪费了内存。(需要考虑:应用程序更加关注什么,如果关注延迟那就适当地增大该值,如果关注内存的使用量那就适当地调小该值。)
  3. 针对 CentOS-6(对应于 2.6.32 内核版本)解决方案

    vm.extra_free_kbytes = 4194304

    • 将extra_free_kbytes 配置为 4G。extra_free_kbytes 在 3.10 以及以后的内核上都被废弃掉了。
  4. 原理示意图

    1-3.处理Page Cache难以回收产生load飙高问题

    • extra_free_kbytes 的目的是为了解决 min_free_kbyte 造成的内存浪费,但是这种做法并没有被内核主线接收,因为这种行为很难维护会带来一些麻烦,感兴趣的可以看一下这个讨论:add extra free kbytes tunable
    • 总的来说,通过调整内存水位,在一定程度上保障了应用的内存申请,但是同时也带来了一定的内存浪费,因为系统始终要保障有这么多的 free 内存,这就压缩了 Page Cache 的空间。调整的效果可以通过 /proc/zoneinfo 来观察
      $ egrep "min|low|high" /proc/zoneinfo 
      ...
      min      7019
      low      8773
      high     10527
      ...
    • min、low、high 分别对应上图中的三个内存水位,可以观察一下调整前后变化。

      说明:内存水位是针对每个内存 zone 进行设置的,所以 /proc/zoneinfo 里面会有很多 zone 以及它们的内存水位。

三、系统中脏页过多引起load飙高

直接回收过程中,如果存在较多脏页就可能涉及在回收过程中进行回写,这可能会造成非常大的延迟,而且因为这个过程本身是阻塞式的,所以又可能进一步导致系统中处于 D 状态的进程数增多,最终的表现就是系统的 load 值很高。

  1. 典型的脏页引起系统 load 值飙高的问题场景

    1-3.处理Page Cache难以回收产生load飙高问题

    • 如图所示,如果系统中既有快速 I/O 设备,又有慢速 I/O 设备(比如图中的 ceph RBD 设备,或者其他慢速存储设备比如 HDD),直接内存回收过程中遇到了正在往慢速 I/O 设备回写的 page,就可能导致非常大的延迟。
  2. 这类问题不好追踪,为了更好追踪这种慢速I/O设备引起的抖动问题,请看Linux Kernel体检的一个patch来进行更好的追踪:mm/page-writeback: introduce tracepoint for wait_on_page_writeback()这种做法是在原来的基础上增加了回写的设备,这样子用户就能更好地将回写和具体设备关联起来,从而判断问题是否是由慢速 I/O 设备导致的(具体分析方法后续补充)
  3. 比较省事的解决方案是控制好系统中挤压的脏页数据。
    通过 sar -r 来观察系统中的脏页个数:
    $ sar -r 1
    07:30:01 PM kbmemfree kbmemused  %memused kbbuffers  kbcached  kbcommit   %commit  kbactive   kbinact   kbdirty
    09:20:01 PM   5681588   2137312     27.34         0   1807432    193016      2.47    534416   1310876         4
    09:30:01 PM   5677564   2141336     27.39         0   1807500    204084      2.61    539192   1310884        20
    09:40:01 PM   5679516   2139384     27.36         0   1807508    196696      2.52    536528   1310888        20
    09:50:01 PM   5679548   2139352     27.36         0   1807516    196624      2.51    536152   1310892        24
    • kbdirty 就是系统中的脏页大小,它同样也是对 /proc/vmstat 中 nr_dirty 的解析,可以通过调小如下设置来将系统脏页个数控制在一个合理范围:

      vm.dirty_background_bytes = 0

      vm.dirty_background_ratio = 10

      vm.dirty_bytes = 0

      vm.dirty_expire_centisecs = 3000

      vm.dirty_ratio = 20

    • 调整这些配置项有利有弊,调大这些值会导致脏页的积压,但是同时也可能减少了 I/O 的次数,从而提升单次刷盘的效率;调小这些值可以减少脏页的积压,但是同时也增加了 I/O 的次数,降低了 I/O 的效率。
    • 多少合适:因系统和业务的不同而异,将这些值调整到业务可以容忍的程度就可以了,即在调整后需要观察业务的服务质量 (SLA),要确保 SLA 在可接受范围内。
    • 调整效果可以根据/proc/vmstat查看
      $ grep "nr_dirty_" /proc/vmstat
      nr_dirty_threshold 366998
      nr_dirty_background_threshold 183275

      这里有一个坑,该解决方案中的设置项如果设置不妥会触发一个内核 Bug,2017年社区提交了一个 patch 将它 fix 掉了,具体的 commit 见writeback: schedule periodic writeback with sysctl , commit log。

扫码领视频副本.gif

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号