I/O スケジューラー
I/O のサブシステム (書き込みの場合) は以下のプロセスにより成り立っている。
- まず、書き込むデータがメモリのディスクキャッシュ上に書き込まれる
- ある程度ディスクキャッシュが溜まると、まだディスクに書き込まれていないデータを I/O スケジューラーに書き込むように (ファイルシステムが) リクエストを送る
- 2 の行程により、I/O スケジューラーのリクエストキューに溜まったリクエストに応じて、デバイスドライバーを利用して物理ディスクにデータを書き込む
上記の I/O スケジューラーがどのようにリクエストを消化するのか見てみよう。
ディスクキャッシュ上では、1 つのファイルの連続したデータは、基本的に連続したメモリ上に書き込まれる。
しかし、それがディスク上で連続しているとは限らない。
あるファイルがどのようにディスク上に書き込まれるかを決めるのがファイルシステムであり、そのリクエストを受けるのが I/O スケジューラーである。
ファイルシステムが I/O スケジューラーにデータ転送リクエストを送る際、物理ディスク上で連続するデータごとにリクエストを分割する処理がファイルシステム側で行われる。この流れは下記のようになっている。
- ファイルシステムは転送対象のデータを物理ディスク上の連続領域ごとにまとめたbio オブジェクトをカーネル内部で作成する
- bio オブジェクトを I/O スケジューラーに渡す
- I/O スケジューラーは受け取った複数の bio オブジェクトを1 つにまとめたリクエストオブジェクトを作成する
- リクエストオブジェクトは I/O スケジューラーのリクエストキューに溜められる
作成したリクエストオブジェクトを実際にどのような順番で処理をするかは I/O スケジューラーの種類による。 例えば、cfq ( Complete Fair Queuing ) スケジューラーは bio オブジェクトを送ったプロセス毎にサブキューを作ることで、かくプロセスのリクエストをなるべく公平に処理する。
I/O スケジューラーの種類を変更する
利用可能な I/O スケジューラーの情報は /sys/bloack/[device-name]/queue/scheduler
に記載されている。echo コマンドで I/O スケジューラー名を書き込むことで、I/O スケジューラーを変更できる。
# 現在の I/O スケジューラー
$ cat /sys/block/xvda/queue/scheduler
noop [deadline] cfq
# cfq に変更
$ echo "cfq" > /sys/block/xvda/queue/scheduler
# 確認
$ cat /sys/block/xvda/queue/scheduler
noop deadline [cfq]
cfq スケジューラーの優先順位
cfq スケジューラーは、ionice コマンドにより、各プロセスの優先順位を設定できる。それぞれ、「Real time」「Best effort」「Idle」
- Real time: システム上のいかなる処理よりも優先される
- Idle: システムがこのプロセス以外にすることがないときに実行される
- Best effort: デフォルトの優先順位で、cfq スケジューラーの通常のロジックに基づいて、公平に I/O が実行される
以下のコマンドで ionice の効果を確認できる。
$ ionice -c 1 dd if=/dev/zero of=/tmp/tmp0 bs=1M count=500 oflag=direct & ionice -c 3 dd if=/dev/zero of=/tmp/tmp1 bs=1M count=500 oflag=direct & wait
[1] 11066
[2] 11067
500+0 レコード入力
500+0 レコード出力
524288000 バイト (524 MB) コピーされました、 8.22118 秒、 63.8 MB/秒
[1]- 終了 ionice -c 1 dd if=/dev/zero of=/tmp/tmp0 bs=1M count=500 oflag=direct
500+0 レコード入力
500+0 レコード出力
524288000 バイト (524 MB) コピーされました、 15.3863 秒、 34.1 MB/秒
[2]+ 終了 ionice -c 3 dd if=/dev/zero of=/tmp/tmp1 bs=1M count=500 oflag=direct
500 MB のファイルを書き出す dd コマンドを2個同時に実行しており、それぞれ Real time クラスと Idle クラスを指定している。Idle クラスの I/O 処理は後回しになるため、Real time クラスの dd コマンドが終わってから、Idle クラスの dd コマンドの処理が始まる。その結果、Idle クラスは Real time クラスの 2 倍の実行速度になっている。ちなみに dd コマンドの oflag=direct オプションはディスクキャッシュを使わずにディスクに書き込む指示で、物理ディスクのパフォーマンス測定に使われる。