文章目录
  1. 1. iotop中对IO百分比的计算
  2. 2. flush线程的io操作

最近的实验中出现了iotop中观测到flush线程io百分比达到了99.99%。这个现象挺出乎意料的,因为在我的印象中flush进程是不应该有io操作的。所以我首先怀疑的是iotop中对io百分比的计算。

iotop中对IO百分比的计算

还是回到iotop的代码。在ui.py中,我们可以发现如下代码

1
2
def delay2percent(delay): # delay in ns, duration in s
return '%.2f %%' % min(99.99, delay / (duration * 10000000.0))

可见进程的io百分比的计算来自于delay占统计时间(在iotop中为1s)的比值。而delay来自于进程TaskStats的blkio_delay_total,内核中具体的定义如下:

1
2
3
4
5
6
7
/* Following four fields atomically updated using task->delays->lock */

/* Delay waiting for synchronous block I/O to complete
* does not account for delays in I/O submission
*/

__u64 blkio_count;
__u64 blkio_delay_total;

内核注释写得很明确了,统计的是同步block I/O的等待时间,并不包括I/O提交延迟。
另一个问题是blkio_delay_total是什么时候被统计的?从内核代码中看,blkio_delay_total是由两个函数delayacct_blkio_start组合使用进行统计的。一个典型也是与本问题相关的使用是io_schedule。

1
2
3
4
5
6
7
8
9
10
11
12
void __sched io_schedule(void)
{

struct rq *rq = raw_rq();

delayacct_blkio_start();
atomic_inc(&rq->nr_iowait);
current->in_iowait = 1;
schedule();
current->in_iowait = 0;
atomic_dec(&rq->nr_iowait);
delayacct_blkio_end();
}

从上面代码看,在线程io调度之前开始统计,在线程调度回来之后结束统计。因而io百分比表示的是因IO被调度出去的时间占墙钟时间的比例。
因而,flush线程这么大io百分比肯定是执行了io操作。

flush线程的io操作

按照我的理解,flush线程的工作应该是将page cache中的dirty页传递到bio层,期间不会涉及到io操作。不过iotop的结果显然被狠狠地打脸了。跟踪一下代码看看。
flush线程在mm/Backing-dev.c文件中被创建:

1
2
kthread_run(bdi_start_fn, wb, "flush-%s",
dev_name(bdi->dev))

线程函数穿越VFS接口最终到了ext4的ext4_da_writepages函数,这个函数负责最终的脏页write-back操作。整个代码过程看起来都很正常,期间还遇到了ext4的日志线程相关(jdb2)处理:

1
2
3
4
5
handle = ext4_journal_start(inode, needed_blocks);
......
ext4_journal_stop(handle);
......
jbd2_journal_force_commit_nested(sbi->s_journal);

这也很好理解,更新操作自然涉及到文件系统日志。然而,到以下几行代码时,我有点儿犯迷糊了

1
2
3
4
5
6
if (!mpd.io_done && mpd.next_page != mpd.first_page) {
if (mpage_da_map_blocks(&mpd) == 0)
mpage_da_submit_io(&mpd);
mpd.io_done = 1;
ret = MPAGE_DA_EXTENT_TAIL;
}

按常理而言,如果io_done未全部完成,继续提交就好了,这个map_blocks有些诡异。跟进去发现,这个mpage_da_map_blocks还涉及到了向磁盘申请Block相关的操作,预感这应该是问题所在了。

文件系统太复杂了,遇到了不太理解的问题,看看有没有哪位填友能帮我答疑解惑。万能的搜索引擎一搜,发现了kai_ding的文章ext4的延迟分配。好文共分享,我决定将这篇文章转载到我的博客中。
从kai_ding的文章中可以看到,ext4提供延迟分配机制:页面在写回时再分配物理磁盘块与之对应。mpage_da_map_blocks()负责分配磁盘页并建立映射关系。
这也就解释了为什么flush线程会有这么大的io百分比。但是99.99%的io占比实在是太令人发指了,相当于flush没有时间干正事了。接下来是如何想办法如何解决它。

文章目录
  1. 1. iotop中对IO百分比的计算
  2. 2. flush线程的io操作