TenForward

技術ブログ。はてなダイアリーから移転しました

4.5 カーネルで stable となった cgroup の単一階層構造 cgroup v2 の io コントローラ

Control Group v2

以前も少し紹介していましたし、連載でも少し触れましたが、今広く (?) 使われている cgroup は色々問題があって、単一階層構造の cgroup が開発されていました。この辺りは

で紹介しました。

以前は開発中の機能だったため、マウントするときに "__DEVEL__sane_behavior" などというふざけたオプションが必要でした。(^^)

この後も順調に (?) 開発はすすみ、4.5 カーネルのリリースでついにこの機能が stable となったようで、"__DEVEL__" というプレフィックスも不要になりましたし、正式な機能で「まともなふるまい」なんてのはないだろうという話があったのかなかったのか知りませんが、名前も "Control Group v2" という名前になったようです。今までのは "v1" です。

ドキュメントは

にあります。

前に試した時は v1 にあったコントローラ (サブシステム) が全部現れていましたが、正式リリースとなった 4.5 の時点で有効なコントローラは memory, io, pid の 3 つだけのようです。

v1 の問題点のひとつに、コントローラがばらばらに実装されているため、コントローラ間の連携ができないという問題がありました。このため、blkio というブロックデバイスに対する I/O 制限を行うコントローラがあるにもかかわらず、通常のファイル I/O (の書き込み) に対する制限ができませんでした (memory と連携できていないため)。

この辺りは「第4回 コンテナ型仮想化の情報交換会@東京」で @hiro_kamezawa さんにお話頂いたので、詳細をお知りになりたい方はそちらをどうぞ。

v2 では、階層構造が単一となって、この辺りの制限ができるようになりました。昨年の LinuxCon で Heo Tejun 氏が ext2 に対応したという話をされていましたが、4.5 を見てみると ext2, ext4, btrfs に対して制限がかかるようです。

というわけで、この制限が働くのか簡単に試してみました。

kernel は 4.6-rc3、ファイルシステムext2ext4 で試しています。

かなり適当な確認なので、間違いとかあるかもしれませんので、気づいたら優しく教えてください。

v1 のおさらい

v2 を試す前に、まずは v1 の blkio コントローラのおさらいをしておきましょう。direct I/O 以外では制限がかかっていないことも確認してみました。

v1 準備

"test01" cgroup を作成して、/dev/vdb に対する 1MB/sec の読み書きの制限を設定してみました。

  1. cgroup 作成
    # mkdir /sys/fs/cgroup/blkio/test01
  2. プロセスを "test01" へ登録
    # echo $$ > /sys/fs/cgroup/blkio/test01/tasks
  3. /dev/vdbに対する制限を設定
    # ls -l /dev/vdb
    brw-rw---- 1 root disk 254, 16 Apr 13 06:30 /dev/vdb (デバイス番号の確認)
    # echo "254:16 1048576" > /sys/fs/cgroup/blkio/test01/blkio.throttle.read_bps_device (読み込み制限)
    # echo "254:16 1048576" > /sys/fs/cgroup/blkio/test01/blkio.throttle.write_bps_device (書き込み制限)
v1 を使った書き込み制限 (direct I/O)
# dd oflag=direct if=/dev/zero of=/data/testfile bs=4K count=1024
1024+0 records in
1024+0 records out
4194304 bytes (4.2 MB) copied, 4.00347 s, 1.0 MB/s

実行時に iostat を実行しました。出力の一部。

Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
vdb             258.59         0.00      1034.34          0       1024
vdb1            258.59         0.00      1034.34          0       1024

書き込みが 1MB/sec に制限されていますね。

v1 を使った読み込み制限 (direct I/O)
# dd iflag=direct if=/data/testfile of=/dev/null bs=4K count=1024
1024+0 records in
1024+0 records out
4194304 bytes (4.2 MB) copied, 4.0018 s, 1.0 MB/s

同様に iostat 出力の一部。

Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
vdb             261.22      1044.90         0.00       1024          0
vdb1            261.22      1044.90         0.00       1024          0

読み込みが 1MB/sec に制限されています。

v1 を使った書き込み制限

"oflag=direct" を指定せずに dd を実行してみると、

# dd if=/dev/zero of=/data/testfile bs=4K count=1048576
^C636264+0 レコード入力
636264+0 レコード出力
2606137344 バイト (2.6 GB) コピーされました、 22.6348 秒、 115 MB/秒
# iostat -p vdb 1 | grep "vdb "
  :(略)
vdb             311.00        12.00    315392.00         12     315392
vdb             339.00        12.00    344064.00         12     344064
vdb             456.57        12.12    434424.24         12     430080
vdb             389.53         4.65    351255.81          4     302080
vdb              11.00         0.00      9216.00          0       9216
vdb              39.00         8.00     33688.00          8      33688
vdb              35.00         0.00     31940.00          0      31940
vdb               0.00         0.00         0.00          0          0
vdb               0.00         0.00         0.00          0          0
  :(略)
vdb               0.00         0.00         0.00          0          0
vdb               0.00         0.00         0.00          0          0
vdb              84.21         4.21     73675.79          4      69992
vdb             140.43         0.00    126012.77          0     118452
vdb              11.11         4.04      9002.02          4       8912
vdb             507.22        12.37    443455.67         12     430152
vdb             410.10        12.12    376501.01         12     372736
vdb               1.00         0.00       912.00          0        912

制限はかかっていませんね。書き込まれたらしばらく 0 の時間があり、また書き込みが再開されているのがわかります。

v1 を使った読み込み制限

"iflag=direct" を外して実行します。実行前にキャッシュクリアします。

# echo 3 > /proc/sys/vm/drop_caches (キャッシュクリア)
# dd if=/data/testfile of=/dev/null bs=4K count=1024 
1024+0 records in
1024+0 records out
4194304 bytes (4.2 MB) copied, 4.0036 s, 1.0 MB/s

読み込みは制限がききますね。

Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
vdb               8.25      1055.67         0.00       1024          0
vdb1              8.25      1055.67         0.00       1024          0

cgroup v2 の io コントローラ

v2 の準備

v2 は "cgroup2" という名前でマウントします。名前以外は以前試した「まともなふるまい」時代とあまり変わりません。

  1. /sys/fs/cgroup にマウント。
    mount -t cgroup2 cgroup /sys/fs/cgroup/
  2. ルート cgroup の確認。ファイルが 3 つだけです
    # ls /sys/fs/cgroup/
    cgroup.controllers cgroup.procs cgroup.subtree_control
  3. 使えるコントローラを確認
    # cat /sys/fs/cgroup/cgroup.controllers 
    io memory pids
  4. "memory" と "io" をサブ cgroup で使えるようにします
    # cat /sys/fs/cgroup/cgroup.subtree_control (サブ cgroup で使えるコントローラ一覧の確認。デフォルトは空)
    # echo "+memory +io" > /sys/fs/cgroup/cgroup.subtree_control (io と memory を追加)
    # cat /sys/fs/cgroup/cgroup.subtree_control (再度確認)
    io memory (登録されている)
  5. "test01" cgroup 作成
    mkdir /sys/fs/cgroup/test01 (作成)
    # ls /sys/fs/cgroup/test01 (test01ディレクトリの確認)
    cgroup.controllers io.max memory.events memory.stat
    cgroup.events io.stat memory.high memory.swap.current
    cgroup.procs io.weight memory.low memory.swap.max
    cgroup.subtree_control memory.current memory.max
    # cat /sys/fs/cgroup/test01/cgroup.controllers (test01で使えるコントローラの確認)
    io memory
    "test01"でioとmemoryが使えるのが確認できました
v2 で direct I/O 制限

まずは v1 でもちゃんと制限された direct I/O を確認しました。

まずは書き込み。

# dd oflag=direct if=/dev/zero of=/data/testfile bs=4K count=1024
1024+0 レコード入力
1024+0 レコード出力
4194304 バイト (4.2 MB) コピーされました、 4.0041 秒、 1.0 MB/秒
Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
vdb             261.22         0.00      1044.90          0       1024
vdb1            261.22         0.00      1044.90          0       1024

読み込み。

#  dd iflag=direct if=/data/testfile of=/dev/null bs=4K count=1024
1024+0 レコード入力
1024+0 レコード出力
4194304 バイト (4.2 MB) コピーされました、 4.00393 秒、 1.0 MB/秒
Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
vdb             261.22      1044.90         0.00       1024          0
vdb1            261.22      1044.90         0.00       1024          0

v1 と同じく制限されています。

v2 で読み込み制限

少し大きなファイルで確認しました。

# echo 3 > /proc/sys/vm/drop_caches
# dd if=/data/testfile of=/dev/null bs=4K count=1048576
^C4605+0 レコード入力
4604+0 レコード出力
18857984 バイト (19 MB) コピーされました、 18.1077 秒、 1.0 MB/秒

iostat の出力は

# iostat -p vdb 1 | grep "vdb "
vdb              30.83      2378.02     10808.93    1864321    8473984
vdb               0.00         0.00         0.00          0          0
vdb               0.00         0.00         0.00          0          0
vdb               0.00         0.00         0.00          0          0
vdb               0.00         0.00         0.00          0          0
vdb               7.07       630.30         0.00        624          0
vdb               8.08      1034.34         0.00       1024          0
vdb               8.00      1024.00         0.00       1024          0
vdb               8.08      1034.34         0.00       1024          0
vdb               8.00      1024.00         0.00       1024          0
vdb               8.08      1034.34         0.00       1024          0
  :(略)

これは v1 と同じように制限がかかります。

v2 で書き込み制限

さて、いよいよハイライト。

# dd if=/dev/zero of=/data/testfile bs=4K count=1048576
^C51563+0 レコード入力
51563+0 レコード出力
211202048 バイト (211 MB) コピーされました、 35.7076 秒、 5.9 MB/秒
# iostat -p vdb 1 | grep "vdb "
vdb              28.16      2182.44      9794.36    1888229    8473984
vdb               0.00         0.00         0.00          0          0
vdb               0.00         0.00         0.00          0          0
vdb               0.00         0.00         0.00          0          0
vdb               0.00         0.00         0.00          0          0
vdb               0.00         0.00         0.00          0          0
vdb               0.00         0.00         0.00          0          0
vdb              36.17       144.68         0.00        136          0
vdb               1.05         0.00       842.11          0        800
vdb               1.01         0.00       517.17          0        512
vdb               1.00         0.00       508.00          0        508
vdb               1.01         0.00       783.84          0        776
vdb               3.00         0.00      1160.00          0       1160
vdb               1.00         0.00      1004.00          0       1004
vdb               1.01         0.00      1034.34          0       1024
vdb               1.01         0.00      1034.34          0       1024
vdb               1.01         0.00      1034.34          0       1024
vdb               1.01         0.00      1034.34          0       1024
vdb               0.99         0.00      1013.86          0       1024
vdb               2.02         0.00      1046.46          0       1036
vdb               2.00         0.00      1024.00          0       1024
vdb               1.01         0.00      1034.34          0       1024

落ち着くまで少し時間があるのと、一瞬 1024 以上の値が出てますが、大体きれいに 1024 (KB) で制限されています。

まとめ

とりあえずディスクへの書き込みがちゃんと制限されているっぽいです (たぶん)。