简介

最近在upstream上, Johannes Weiner发了一个memdelay的patch, 主要是衡量系统内存的健康程度, 在对它进行分析和优化之后, 做了一个简单的总结

memdelay是衡量一个系统(memcg)中内存的健康程度的一个监控系统, 可以用来评价一个memcg的limit是否设置得合理

主要功能

  • 监控每个task因为内存短缺导致的延迟
  • 监控每个memcg因为内存短缺导致的延迟
  • 监控每个memcg因为内存短缺产生了多大的性能影响

为什么需要它

在一个系统中, 能跑多少应用, 跑少了, 浪费内存, 跑多了, 性能下降, 多少是个合理的值, 是个比较难捉摸的事情, memdelay就是为此来做一个简单的评估

一个很简单的模型, 应用一共需要1g的内存, 如果提供了1g的内存给他, 那么就什么问题都没有了, 但是实际情况中, 很多内存都是read_once, 所以为了提高利用率, 给他900m也是能跑的, 只不过这些内存都分时复用了, 一般情况下, 给个800m, 也能跑, 700m也能跑, 分时复用得越厉害, 性能就会越差. 那么临界点是多少, 让memdelay来告诉你

原理介绍

memdelay的思想很简单, 就是在一个memcg中, 因为内存短缺引起的延迟除以任务实际运行时间的百分比. 如果系统内存很富裕的话, 这个时间基本上为0. 在内存很紧张的情况中, 这个百分比可以达到50%, 可以说系统一半时间在干活, 一半时间在做内存这件事情上白忙.

主要设计结构

这个简单介绍一下设计概要, 把cpu的运行状态分3个种类

  • MDS_NONE, 表示没有任何内存造成的延迟
  • MDS_SOME, 表示既有内存延迟, 又有其他延迟, 比如IO
  • MDS_FULL, 只有内存延迟

接口设计

memdelay的接口是memcg目录下的文件memory.memdelay,

cat memory.memdelay
18359583 17087353 1272230 (总的内存延迟 前台延迟 后台延迟)
0.46 0.11 0.03 (MDS_SOME状态1分钟, 5分钟, 15分钟, 百分比)
3.97 2.09 0.85 (MDS_FULL状态1分钟, 5分钟, 15分钟, 百分比)

百分比越高, 说明越多的时间花在了内存复用上, 对性能的影响比较大

那如何把cpu区分出这3种状态, 那就是根据这个cpu上不同性质的task的数量来定

把每个task根据内存的状况, 分别记成sleep, iowait, runnable, delayed, delayed_active, 分别表示的含义是

  • sleep, task睡眠, 不在runqueue上
  • iowait, 在等io
  • runnable, 处于runqueue上
  • delayed, 因为内存短缺, 目前没在运行, 比如进入direct reclaim之后, 被调度出去了
  • delayed_active, 因为内存短缺, 正在运行, 比如正在做direct reclaim

那么如何判断一个task是处于sleep, iowait, runnable, delayed, delayed_active中的哪种状态呢, 这就需要在系统中, 记录任务状态的变化过程, 从代码的实现角度简单得来说, 就是在调度对task进行处理的时候插桩

图片.png

根据上面所诉的根据内存的使用情况来对task的状态分类, 从而来确定cpu的状态, 判断规则如下

  • 有delayed_active的任务下, 有iowait为MDS_SOME, 否则就是MDS_FULL
  • 有delayed的任务下, 有runable或者iowait为MDS_SOME, 否则就是MDS_FULL
  • 其他情况就是MDS_NONE

memcg内存延迟统计

每个memcg建立一个per cpu的数据结构memdelay_domain_cpu, 记录cpu的这3种状态, 每5s统计一次, 就可以计算出一个memcg里面所有cpu, MDS_NONE占多少百分比, MDS_SOME占多少百分比, MDS_FULL占多少百分比, 就可以看出内存影响了多少的性能

测试检验

以下是从测试的角度来检验以下memdelay的功能

/sdk目录下有17G的文件, 用来准备做buffer io
time sh -c 'vmtouch -e  /sdk/*; vmtouch -t /sdk/*'

在没有memcg的限制的情况下, time结果, (memdelay的结果肯定全是0, 因为没有前台延迟)

real    0m32.044s
user    0m1.192s
sys     0m9.052s

在把memcg限制到1G的情况下, time结果

real    0m36.561s
user    0m0.961s
sys     0m16.177s

memdelay的结果

4191438 4191438 0
0.00 0.00 0.00
4.52 1.04 0.34

从上面的结果可以看出, memcg限制为1g的时候, 前台回收总共延迟了4s, 刚好是上面的32s到36s的差距, 4s/36s等于1/9, 也就是0.11, 在百分比的那一栏, 第一列是1分钟的滑动平均, 因为只跑了30s, 所以只有一半, 4.52%也很好得体现了内存前台延迟对应用拖慢了多少性能