cgroup でプロセス毎のDisk (block device) へのI/O の帯域制限 blkio.throttle.*

redhatのcgroupのdocument見ていてDisk I/Oの帯域制限できたら完璧なのになー、と思っていたんだけど、cgroup/blkio/ 内のファイルを見ていたらたらblkio.throttle.* というそれっぽいファイルを発見。最新のkernelのdocument内にも見つけたので、redhatの日本語documentが古いだけかな。

# ls /cgroup/blkio/
blkio.io_merged         blkio.reset_stats                blkio.throttle.write_bps_device   libvirt
blkio.io_queued         blkio.sectors                    blkio.throttle.write_iops_device  notify_on_release
blkio.io_service_bytes  blkio.throttle.io_service_bytes  blkio.time                        release_agent
blkio.io_service_time   blkio.throttle.io_serviced       blkio.weight                      tasks
blkio.io_serviced       blkio.throttle.read_bps_device   blkio.weight_device
blkio.io_wait_time      blkio.throttle.read_iops_device  cgroup.procs
  • blkio.throttle.io_service_bytes
  • blkio.throttle.io_serviced
  • blkio.throttle.read_bps_device
  • blkio.throttle.read_iops_device
  • blkio.throttle.write_bps_device
  • blkio.throttle.write_iops_device

libvirt (kvm) 仮想マシンのdisk I/O を制限する例

仮想マシンのイメージファイルを仮想ホストの/dev/sda に置いているとする。blkio サブシステムではデバイスごとにパラメータを設定するので、まず /dev/sda のmajor, minor 番号を調べる。
(ここで言っているデバイスは仮想マシン上の/dev/sda, /dev/vda などではなく、ホストOS上のデバイス)

# ls -l /dev/sda
brw-rw---- 1 root disk 8, 0  4月 15 16:10 2012 /dev/sda

=> major 8, minor 0

cgconfig を有効にしている状態で、libvirtdを起動すると/cgroup/*/libvirt/qemu/test1 のグループを作成してtasksにqemu-kvm その他関連するpidを書き込んでくれる。これを利用して、/etc/cgconfig.conf に

group libvirt/qemu/test1 {
  blkio {
    blkio.throttle.read_bps_device =  "8:0 20000000";
    blkio.throttle.write_bps_device = "8:0 20000000";
  }
}

これを書いてcgconfig restart 後にlibvirtd を再起動、仮想マシン test1 を起動。

# service cgconfig restart
# service libvirtd restart
# virsh start test1
$ more /cgroup/blkio/libvirt/qemu/test1/tasks
3218
### qemu-kvm のpid 等が書き込まれていることを確認
$ more /cgroup/blkio/libvirt/qemu/test1/blkio.throttle.*_bps_device
::::::::::::::
/cgroup/blkio/libvirt/qemu/test1/blkio.throttle.read_bps_device
::::::::::::::
253:3   20000000
/cgroup/blkio/libvirt/qemu/test1/blkio.throttle.write_bps_device
::::::::::::::
253:3   20000000

この状態でvm test1 上からddを実行して、1Gのファイルを作成する。サイズは適当だけど割当てメモリに対して小さすぎるとバッファに載ってしまいそうなので、適当に大きいサイズで。

write
# virsh console test1
Connected to domain test1
エスケープ文字は  ^] です 

Scientific Linux release 6.2 (Carbon)
Kernel 2.6.32-220.el6.x86_64 on an x86_64

test1 login: root
Password: 
Last login: Fri Apr 15 07:59:11 on tty1
# dd if=/dev/zero of=/tmp/hoge.dat bs=1M count=1000
1000+0 records in
1000+0 records out
1048576000 bytes (1.0 GB) copied, 49.221 s, 21.3 MB/s

ほぼ設定値通りの20MByte/secになった。ちなみにcgroupを設定していない状態だとwriteは120MByte/secぐらい出た

read
# time dd if=hoge.dat of=/dev/null bs=1M count=2048
2048+0 records in
2048+0 records out
2147483648 bytes (2.1 GB) copied, 2.61108 s, 822 MB/s

real    0m2.619s
user    0m0.004s
sys     0m1.522s

822MB/sec !? 明らかに早すぎる。おかしい。キャッシュのせいだろう。ということで仮想マシンのバッファキャッシュをクリアして再挑戦。

# sync
# echo 3 > /proc/sys/vm/drop_caches
# echo 0 > /proc/sys/vm/drop_caches
# time dd if=hoge.dat of=/dev/null bs=1M count=2048
2048+0 records in
2048+0 records out
2147483648 bytes (2.1 GB) copied, 2.76242 s, 777 MB/s

real    0m2.775s
user    0m0.003s
sys     0m1.518s

777 MB。やっぱりまだ早い。うーん、readは制限きかない?と思ったところで、いやこれは仮想ホスト上でキャッシュしてるからだろうと推測して、仮想ホスト上でもキャッシュをクリア。

# sync
# echo 3 > /proc/sys/vm/drop_caches
# echo 0 > /proc/sys/vm/drop_caches

そして再度仮想マシン上でddを実行。

# time dd if=hoge.dat of=/dev/null bs=1M count=2048
2048+0 records in
2048+0 records out
2147483648 bytes (2.1 GB) copied, 106.986 s, 20.1 MB/s

real    1m47.032s
user    0m0.007s
sys     0m2.288s

こちらも設定値とおり、ほぼ20Mbyte/secになった。

*1:実際にI/Oが集中して困るのはwriteのほうなので、readは制限しなくても良い or もっと緩い値でもいいかも