LXCで学ぶコンテナ入門 -軽量仮想化環境を実現する技術

第5回 Linuxカーネルのコンテナ機能[4] ─cgroupとは?(その3)

この記事を読むのに必要な時間:およそ 6.5 分

blkioサブシステム

blkio(ブロックI/O)サブシステムは,cgroup内のタスクのブロックデバイスへのI/Oを制御したり,cgroup内のタスクがどれくらいブロックデバイスへのアクセスを行ったかの統計値を取得するのに使えます。

では,cgroup内のタスクのブロックデバイスに対する帯域制限をかけてみましょう。まずはこれまでと同様に/sys/fs/cgroup/blkioというサブシステム専用のディレクトリを作成してから,blkioサブシステムを指定してマウントし,テスト用のcgroup test1を作成します。その後,test1グループに対して現在のシェルのPIDを登録します。

$ sudo mount -n -t cgroup -o blkio cgroup /sys/fs/cgroup/blkio/ (blkioサブシステムのマウント)
$ sudo mkdir /sys/fs/cgroup/blkio/test1
$ echo $$ | sudo tee -a /sys/fs/cgroup/blkio/test1/tasks 
25462

ここでは/dev/vdbに対して単位時間辺りに書き込める量に制限をかけてみます。この時使用するファイルは以下のファイルです。

blkio.throttle.read_bps_device
デバイスからの読み込みの制限値(バイト/秒)
blkio.throttle.write_bps_device
デバイスへの書き込みの制限値(バイト/秒)

制限をかけるにはデバイスのノード番号が必要です。このノード番号と制限値を以上のファイルに書き込むことで制限できます。またblkioで制限ができないデバイスのノード番号を指定したり,/dev/vdb1などのパーティションを指定したりするとエラーで書き込めません。

$ ls -l /dev/vdb
brw-rw---- 1 root disk 253, 16 Jun 16 15:03 /dev/vdb

/dev/vdbのノード番号は 253:16 ですので,この番号と制限値として1Mバイト/秒をこれらファイルに書き込みます。まずは書き込みの制限です。

$ echo "253:16 1048576" | sudo tee /sys/fs/cgroup/blkio/test1/blkio.throttle.write_bps_device 
253:16 1048576
$ cat /sys/fs/cgroup/blkio/test1/blkio.throttle.write_bps_device 
253:16  1048576

無事書き込めていますね。複数のデバイスに対する設定を行う場合は,上記のような操作を繰り返し行います。

$ echo "253:0 1048576" | sudo tee /sys/fs/cgroup/blkio/test1/blkio.throttle.write_bps_device
253:0 1048576
$ cat /sys/fs/cgroup/blkio/test1/blkio.throttle.write_bps_device 
253:0   1048576
253:16  1048576

/dev/vdaのノード番号である253:0に対する制限を書き込むと,デバイスごとの制限値が書き込まれているのが確認できます。

制限を取り消したい場合は制限値として0を書き込みます。

$ echo "253:0 0" | sudo tee /sys/fs/cgroup/blkio/test1/blkio.throttle.write_bps_device 
253:0 0
$ cat blkio.throttle.write_bps_device 
253:16  1048576

先ほど存在していた/dev/vdaに対する制限が消えていますね。

さて,この制限がきちんと効いているか確認してみましょう。

$ sudo dd if=/dev/zero of=/data/testfile bs=4K count=1024 oflag=direct
1024+0 records in
1024+0 records out
4194304 bytes (4.2 MB) copied, 4.00925 s, 1.0 MB/s

きちんと設定通りの値になっていますね。同様に読み込みの制限を設定してみましょう。

$ echo "253:16 1048576" | sudo tee /sys/fs/cgroup/blkio/test1/blkio.throttle.read_bps_device
253:16 1048576
$ dd if=/data/testfile of=/dev/null bs=4K count=1024 iflag=direct
1024+0 records in
1024+0 records out
4194304 bytes (4.2 MB) copied, 4.00191 s, 1.0 MB/s

書き込みと同様に制限がされているのがわかりますね。ここでは単位時間あたりのバイト数で制限しましたが,IOPSでも制限できます。

上記のような設定を行うと,以下のファイルでそのデバイスとの間で転送されたバイト数やIOの回数を確認できます。

blkio.throttle.io_serviced
IO操作の回数
blkio.throttle.io_service_bytes
転送されたバイト数

これも確認しておきましょう。

$ cat /sys/fs/cgroup/blkio/test1/blkio.throttle.io_serviced
253:16 Read 1027
253:16 Write 1024
253:16 Sync 2051
253:16 Async 0
253:16 Total 2051
Total 2051
$ cat /sys/fs/cgroup/blkio/test1/blkio.throttle.io_service_bytes 
253:16 Read 4206592
253:16 Write 4194304
253:16 Sync 8400896
253:16 Async 0
253:16 Total 8400896
Total 8400896

I/OスケジューラとしてCFSスケジューラを使用している場合は,帯域制限だけでなく,cgroup間の重みづけの配分も設定できます。また,以上で紹介した以外にもblkioサブシステムではいろいろなパラメータを確認できます。詳しくはカーネル付属文書のblkio-controller.txtをご覧ください。

補足(2015/07)

現時点では,blkioサブシステムはダイレクトI/Oのみを対象としています。ページキャッシュを使ったBuffered I/Oの書き込みの制限ができません。

これは,現在のCgroupはサブシステムごとに独立して動作するためです。Buffered I/Oの制限をするにはメモリが関係しますが,blkioサブシステムとmemoryサブシステムが連携して動作できないためです。

perf_eventサブシステム

perf_eventサブシステムを使うと,Linuxの解析ツールであるperfでcgroupを指定した解析が行えます。

カーネル付属文書のperf-record.txtperf-stat.txtにcgroupの指定方法が載っています。

net_prioサブシステム

net_prioサブシステムは,cpuやblkioサブシステムの相対配分や重みづけ配分のように,複数のcgroupの間の優先度を割り当てます。インターフェースごとに優先度が設定できます。

優先度の設定と設定の確認にはnet_prio.ifpriomapファイルを使います。ここまでの例と同様に/sys/fs/cgroup/net_prioディレクトリにマウントして試してみましょう。

ここの例はUbuntu 12.04 LTSにlinux-current-genericカーネルを入れて試しています。12.04 LTS標準の3.2カーネルではnet_prioサブシステムはまだ存在しないためです※1⁠。

$ sudo modprobe netprio_cgroup (net_prioのモジュールをロード)
$ sudo mount -n -t cgroup -o net_prio cgroup /sys/fs/cgroup/net_prio
$ sudo mkdir /sys/fs/cgroup/net_prio/test1
$ sudo mkdir /sys/fs/cgroup/net_prio/test2

ここではcgroupfsをマウントしたあと,test1test2という2つのグループを作成しました。まずはどのように制限値が設定されているか,このファイルの中を見てみましょう。

$ cat /sys/fs/cgroup/net_prio/test1/net_prio.ifpriomap 
lo 0
eth0 0
$ cat /sys/fs/cgroup/net_prio/test2/net_prio.ifpriomap 
lo 0
eth0 0

このようにインターフェースごとの優先度の値が書かれています。cgroupを作成した時のデフォルト値は親グループのnet_prio.ifpriomapの値が使われます。

それではここで作成した2つのグループに優先度を設定してみます。test1グループに1を,test2グループに10を設定します。数字が大きい方が優先度が高くなります。

$ echo "eth0 1" | sudo tee /sys/fs/cgroup/net_prio/test1/net_prio.ifpriomap 
eth0 1
$ echo "eth0 10" | sudo tee /sys/fs/cgroup/net_prio/test2/net_prio.ifpriomap 
eth0 10
$ cat /sys/fs/cgroup/net_prio/test1/net_prio.ifpriomap 
lo 0
eth0 1
$ cat /sys/fs/cgroup/net_prio/test2/net_prio.ifpriomap 
lo 0
eth0 10

それぞれのグループのnet_prio.ifpriomapファイルを見ると,eth0に対する優先度がそれぞれ1と10に設定されており,test2グループの方が優先度が高く設定されました。

net_prioグループについては,カーネル付属文書のnet_prio.txtもご覧ください。

※1)
執筆時点ではlinux-image-3.13.0-30-genericというカーネルがインストールされました。

hugetlbサブシステム

HugeTLBはメモリを管理する単位であるページのサイズを大きくすることで,たくさんのメモリを使うアプリケーションのパフォーマンスを改善する仕組みです。hugetlbサブシステムはこのHugeTLBをcgroupから扱うことのできる機能です。詳しくはカーネル付属文書のhugetlb.txtをご覧ください。

nsサブシステム

nsサブシステムは前回の表1では紹介しませんでした。なぜかと言いますと,nsサブシステムはいろいろと実装に問題があったため,3.0カーネルで削除されたためです。

元々は名前空間機能と連携してcgroupを作成する機能でした。2.6.37カーネルがリリースされた際に,cpusetサブシステムのところで説明したcgroup.clone_children機能が実装されるとともに,廃止予定の機能となり,3.0で廃止されました。

2.6.32カーネルを使用しているRHEL/CentOS 6ではこの機能が有効です。しかし,このサブシステムはマウントしない方が無難でしょう。RHEL/CentOS 6上でLXCを動かす場合は,このサブシステムをマウントしているとうまく動きません。

著者プロフィール

加藤泰文(かとうやすふみ)

2009年頃にLinuxカーネルのcgroup機能に興味を持って以来,Linuxのコンテナ関連の最新情報を追っかけたり,コンテナの勉強会を開いたりして勉強しています。英語力のない自分用にLXCのmanページを日本語訳していたところ,あっさり本家にマージされてしまい,それ以来日本語訳のパッチを送り続けています。

Plamo Linuxメンテナ

Twitter:@ten_forward
技術系のブログ:http://tenforward.hatenablog.com/