昨日のエントリに続いて、そのまま勢いでcgroupsを使ってデバイスI/Oを制御するツールをPerlで書いてみました。
プロセス単位でCPUコアを割り当てたりもできるけど、そんなニーズあるのかなぁと思ったのでそっちはとりあえずPending。このシリーズで後やるとしたら、プロセス単位でトラフィックの制御とメモリぐらいを考えていますが、cgroupやCFSをもう少し勉強すると、もっとやりたいことが出てくるかもしれません。
昨日公開したCPU制御のレポジトリ名をresources-managed-toolsにリネームして、そこにツールをどんどん入れていくことにしました。引数で色々やれるツールでも良いのですが、この手のツールはツール自体が別の方が運用ミスが少なくなる印象があるので、あえて別ツールにしました。
ブロックデバイスI/OをByte/secで制御
readもwriteも制御することができます。例えばwriteを制御する場合に、以下のようなコマンドでI/Oが走っていたとします。
dd if=/dev/zero of=/root/io_test.4G bs=4K count=1048576 oflag=direct
/rootは/dev/sda1にマウントされています。実際に実行して、piotop.plでプロセス単位のI/Oを見てみると以下のようになります。
-- Every 3 sec --
19:50:54 up 3 days, 14:01, 5 users, load average: 0.62, 0.17, 0.10
pid state read write command cwd_path
14293 D (disk sleep) 0bps 159Mbps dd /root
32373 S (sleeping) 96Kbps 7Mbps btrfs-endio-wri /
892 S (sleeping) 0bps 0bps sedispatch /
882 S (sleeping) 0bps 0bps acpid /
14319 S (sleeping) 0bps 0bps btrfs-worker-2 /
このように、writeが159Mbit/sec生じているのがわかります。そこで、以下のコマンドでwriteを40Mbit/secに制限してみましょう。writeの場合は、change-write-bps-rateを使います。
./change-write-bps-rate -p 14293 -d /dev/sda -r 5
引数にpidとrateとデバイスを指定します。rateはMbyte/secで渡して下さい。なので、上記コマンドでは5 * 8 Mbit/secを指定したことになります。すると以下のようになります。
-- Every 3 sec --
19:52:29 up 3 days, 14:02, 5 users, load average: 1.20, 0.48, 0.21
pid state read write command cwd_path
14293 D (disk sleep) 0bps 39Mbps dd /root
32373 S (sleeping) 352Kbps 2Mbps btrfs-endio-wri /
892 S (sleeping) 0bps 0bps sedispatch /
882 S (sleeping) 0bps 0bps acpid /
14319 S (sleeping) 0bps 0bps btrfs-worker-2 /
きちんとwriteが40Mbpsに制限されていますね。素晴らしい!
また、readの場合は以下のようなコマンドを実行します。引数の与え方はwriteの場合と同じです。change-read-bps-rateを使います。
./change-read-bps-rate -p 14293 -d /dev/sda -r 10
これで10Mbyte/sec、つまりは80Mbit/secにreadを制限することができます。これらの制限を解除するには、readもwriteも同様にrateに0をわたします。/sys/fs/cgroup以下のゴミ掃除も行なってくれます。
./change-write-bps-rate -p 14293 -d /dev/sda -r 0
これで、とても簡単にプロセスのI/Oを制御できますね。
ブロックデバイスI/Oをiopsで制御
bpsだけでなく、時にはiopsで制御したい場合もあります。そこで、iopsでも制御できるようにツールを作っておきました。これらの使い方は、ほとんどchange-{write,read}-bps-rateと同じようにchange-{write,read}-iops-rateを使って以下のように実行します。例えば、以下のようなコマンドを実行するとします。
dd if=/dev/zero of=/root/io_test.4G bs=4K count=1000000 oflag=direct
今回はpiotop.plの出力は省力します。この場合、4k * 1000000バイト、つまりは約4Gbyteのファイルを作成することになります。(計算しやすいようにあえて1024で計算しないようにしています)このコマンド実行時に、以下のコマンドを実行します。
./change-write-iops-rate -p 14293 -d /dev/sda -r 1000
これによって、1秒間に1000回のI/Oオペレーションを行う事になります。そのため、4kのブロックサイズで1000000回の書き込みオペレーションが行われるので、1000000 / 1000で約4GByteのファイルを1000秒で作成することになります。iops単位の制御なので、このブロックサイズが例えば8kや別のサイズであっても、デバイスがボトルネックにならない限りは1000秒で作成されます。
なので、大体計算するとブロックサイズ4kの場合は、約4Mbyte/sec(32Mbit/sec)ぐらいの速度でwriteが行われると考えられます。change-read-iops-rateでreadの制御も同様にできますが、ほぼ同じなので説明は省略します。
最後に
I/Oの負荷は、他のサービスを巻き込んだりして運用上とても困る事が多いので、こういう簡単なツールを使って運用者が楽に運用できて、安定したサービスを提供できるようになると良いですね。piotop.plでI/O高いプロセスを調査して、resourses-managed-toolsでビシっと制御する、という使い方が良いのではないでしょうか。さてさて、ではまたcgroupの勉強に戻ります。
「勢いでデバイスI/Oを制御するツールも作った」への1件のフィードバック
コメントは受け付けていません。