使用ftrace跟踪块设备:跟踪函数级别的IO流程。例如write过程很慢,到底慢在哪一步,就可以通过ftrace跟踪时间,可以查看走过的函数以及每一步的时间消耗。依赖于/sys/kernel/debug/的存在。
blktrace/blkparse可以跟踪block级别的IO操作分析,可以看到做了哪些IO操作。
iotop 可以看每个进程的IO流量情况。
iostat 可以看到每个硬盘上的IO流程情况。例如:
cd /sys/block/sda/queue
iostat -txz 1
基于cgroup的IO
我们可以将一些进程加到一个cgroup,另一些进程加到另一个cgroup里面。两个group可以配置不同的权重,相当于基于group来设置ionice。例如:
在/sys/fs/cgroup/blkio中,创建A和B两个group:
cd /sys/fs/cgroup/blkio
mkdir A
mkdir B
1
2
3
然后修改A和B的权重(权重越高,拿到的io使用率就越高。看看默认权重是多少,可设置的weight值的范围是多少):
cd A; echo 100 > blkio.weight
cd ../B; echo 10 > blkio.weight
1
2
我分别在指定cgroup里执行IO型程序 dd if=/dev/sda of=/dev/null ,即一直读/dev/sda的内容:
cgexec -g blkio:A dd if=/dev/sda of=/dev/null &
cgexec -g blkio:B dd if=/dev/sda of=/dev/null &
1
2
然后通过iotop去看两个进程的io占用率:
iotop
就可以看到属于A的进程的io速率就远高于B的进程了。
注意,在使用cfq的IO调度算法时(通过/sys/block/sda/queue/schedule查看和修改),weight才起作用,其他的调度算法就没作用。
还可以限制某个group的bio的流量。例如:
/sys/fs/cgroup/blkio
cd A
echo "8:0 1048576" > blkio.throttle.read_bps_device
1
2
3
其中8:0是设备的主次设备号,1048576是以字节为单位的速率限制,那么这里就限制了设备8:0的读速率最大为1MB。
运行一个io程序:
cgexec -g blkio:A dd if=/dev/sda of=/dev/null &
1
通过iotop就可以看到(DISK READ列)读速率被限制了。修改速率值可以看到读速率的变化。
上面是限制读,限制写的话就是修改write_bps_device:
echo "8:0 1048576" > blkio.throttle.write_bps_device
1
运行一个io程序,写300MB数据到文件/mnt/a:
cgexec -g blkio:A dd if=/dev/zero of=/mnt/a oflag=direct bs=1M count=300 &
1
通过iotop就可以看到(DISK WRITE列)写速率被限制了。修改速率值可以看到写速率的变化。
但这个功能有个缺陷,在cgroup v1版本里面,对于write,你只能限制direct io形式的写的流量,因为如果你先写进page cache,由内核后台线程再去写磁盘的,你并没有将这个内核线程放到cgroup里面,并且这个回写线程是为所有io服务的,是整个系统范围的writeback,也就是说它也负责其他cgroup的进程的写,因此也不能简单地将这个内核线程加到某一个cgroup里面。
所以在cgroup v2中,对于放进blkio cgroup的进程,它同时会监控这个group里面的进程的dirty情况,因此能够通过控制dirty pages的写回流量来控制blkio流量。
cgroup的版本是要在kernel里面选择的,kernel同时支持这两种cgroup。(好像在kernel 4.2才引入??)