Iowait的成因、对系统影响及对策

上一篇 / 下一篇  2014-01-24 13:57:41 / 个人分类:性能基本概念

什么是iowait?
顾名思义,就是系统因为io导致的进程wait。再深一点讲就是:这时候系统在做io,导致没有进程在干活,cpu在执行idle进程空转,所以说iowait的产生要满足两个条件,一是进程在等io,二是等io时没有进程可运行。

Iowait是如何计算的?
先说说用户如何看到iowait吧
我们通常用vmstat就能看到iowat,图中的wa就是(标红)

这个数据是vmstat经过计算文件/proc/stat中的数据获得,所以说大家看到的是能够大概反应一个系统iowait水平的数据表象。关于/proc/stat中的数据都代表了什么意思,大家自己google吧,不再赘述。

那/proc/stat文件中的这些数据是从哪来的呢?
Kernel中有个proc_misc.c文件会专门输出这些数据,这个文件对应的函数是show_stat
部分代码:

这部分代码会输出你在/proc/stat中看到的数据,通过代码我们得知iowait来自
iowait = cputime64_add(iowait, kstat_cpu(i).cpustat.iowait);

那么 cpustat.iowait是谁来修改的呢?
我们找到了这个函数account_system_time

我们可以看出,当某个cpu产生iowait时,那么这个cpu上肯定有进程在进行io,并且在等待io完成(rq->nr_iowait>0),并且这个cpu上没有进程可运行(p == rq->idle),cpu在idle。

谁在产生iowait?
那么是谁修改了rq->nr_iowait呢?
重点终于来了,呵呵。

所以产生iowait的根源被我们找到了,就是函数io_schedule, io_schedule_timeout,顾名思义,这两个函数是用来做进程切换的,而且切换的原因是有io。只不过io_schedule_timeout还给出了一个sleep的时间,也就是timeout。

systemtap来跟一下到底是谁在什么时候调用了这两个函数?
在这里我们以引擎为例子,trace进程searcher_server

Stap脚本Block.stp:(只截取了部分程序)

程序的大意就是在1S内,统计哪个进程分别调用了多少次这两个函数。并且把调用时的堆栈print出来,这样能更清楚地看到到底是哪个系统调用跑到了这个地方。

在最正常的状态下,跑一下机器:

此时新 引擎 searcher QPS有1500+,cpu busy有88%,iowait几乎为0,内存在mmap时全部用MAP_LOCKED被锁在内存中

跑了一会发现并没有调用到io schedule,这也符合我们的预期。
我们再一边跑dd一边stap抓取

sudo stap block.stp pid 5739 -DMAXSKIPPED=1000000 > directdd
起两个dd进程,写10G的数据,不走page cache,direct写
dd if=/dev/zero f=a count=20000000 flag=direct
dd if=/dev/zero f=b count=20000000 flag=direct
一共写20G

  • Searcher表现:
  • Cpu busy & iowait

    Latency:

    可以看出direct dd产生的iowait极小,最高才1.4左右,但是对searcher却也造成了不小的影响,通过vmstat的结果来看,当执行dd之后进程上下文切换从2W+飙到了8W+,被block的searcher线程为个位数。

  • 被block的线程堆栈:
  • 写log

  • 被block的频率
  • 经stap追查发现,切换次数的增加都是由于direct dd导致的:
    由于是direct写,所以每写一次都要做io schedule

  • 小结:
  • Searcher latency上升和searcher相对温和的io schedule、进程切换都有关系,但是这时的主因应该是进程切换,进程切换还会造成频繁的进程迁移,TLB flush ,Cache pollution。

    再做一次新的实验,把dd的direct flag去掉,让page cache生效
    Searcher的运行环境和运行压力和上同

  • Searcher表现:
  • Cpu busy & iowait:

    Latency:

    可以看出带page cache的dd对searcher影响更大,我们先看一下vmstat抓取到的数据

    平均被block的线程数据很多,甚至在某个时刻可以运行的线程数量为0

  • searcher被block时的堆栈:
  • block layer写请求

    Sync buffer

    此时的dirty ratio已大于40%,需要做blk_congestion_wait,这个可以算是最严厉的惩罚了。。

    Searcher用到的某些页被刷出去,需要sync page read

  • 被block的频率:
  • 小结:
  • 当带page cahce进行dd时,很容易就能达到10%的background dirty ratio和40%的dirty ratio,达到40%的时候buffered write就变成了sync write。经stap trace发现每次blk_congestion_wait都要耗时100ms左右,也就是说一个线程要被block 100ms,很致命。

    为了减少io的影响,我们把log给禁掉
    再做一次实验

  • Searcher表现:
  • Cpu busy & iowait

    Latency:

    把写log关掉之后竟然还有iowait,是谁造成的呢?

  • Searcher被block时的堆栈:
  • 我们的内存都被mlock了,竟然还有sync page,为啥呢?
    用blktrace和debugfs追了一下,发现竟然是一个算法数据的问题
    /path/of/data
    原来是这个文件的数据被dd给刷出去了,导致还要重新read到内存
    然后写了个程序把这个数据也lock到内存中
    ./lock /path/of/data

    Lock数据再重新跑dd with page cache

  • Searcher 表现:
  • Cpu busy & iowait:

    Latency:

    可以看到,iowait水平又降低了不少,那么此时此刻,谁还在制造iowait呢?

  • Searcher被block时的堆栈:
  • 原来是内存很少了,导致申请内存时要走到try_to_free_pages(平时极少走到),走到这一步说明系统内存已经少的可怜。但是没办法,谁让searcher还要去malloc呢,这些malloc来自两部分:1,mempool申请的内存,其实这个是完全可以抹掉的 2,算法so中STL部分用到的内存。

  • 小结:
  • 关掉log,将数据都lock在内存中,降低了iowait的水平,但是要让searcher不受影响,还要做更多的工作,比如不申请内存。

    如何消除searcher(或应用系统)的iowait?
    1, 没有io
    不写log,或者把写log的事情交给一个专门线程来做,searcher不做buffered write;不做disk read,尤其是sync page这类操作。
    2, 全内存且不申请内存
    用到的数据read once,全内存且lock住;把mempool做到完美,起码做到99%的case不做内存申请。
    3, 尽量减少其他应用的io影响
    其实就是能将dd的负面影响降到最少,如用cgroup;在scp多个大文件的时候,在传输过程中及时清理每个大文件的page cache,将系统的dirty ratio维持在10%以下,尤其是不能达到40%。

    转:http://www.searchtb.com/2013/02/iowait_why_and_optimization.html


    TAG:

     

    评分:0

    我来说两句

    Open Toolbar