Deadlineスケジューラの概要
キューに入ったリクエストに対して処理までの期限(Deadline)を設定し、期限を過ぎているリクエストが無ければ、可能な限りリクエストをセクタ順にソートする。デッドラインを過ぎているリクエストを優先で処理することで、レイテンシを一定に保つことを目指したスケジューラです。
- ディスパッチキューの他に4つのキューを持っています。セクタ順に並べ換えるためのソートキュー(sort_list)と、リクエストの期限(Deadline)を管理するためのデッドラインキュー(fifo_list)の2種類×Read/Writeで4つのキューになります。
- FIFOで管理されるデッドラインキュー(fifo_list)により、リクエストに対して最長の待ち時間を保証するように試みます。これによりリクエスト毎の最長の待ち時間を一定に保つてるようになります。
- デフォルト設定ではWriteよりもReadが優先される設定となってます。(Writeは非同期、Readは同期であることが多いため)
- 複数I/Oリクエストを纏めてバッチで送ります。バッチは、ReadもしくはWriteのリクエストを纏めたものです。(詳細はfifo_batchの項で書きます)
チューニングパラメータ
パラメータ | デフォルト値 | |
---|---|---|
write_expire | 5000(ms) | Writeリクエストの期限 |
read_expire | 500(ms) | Readリクエストの期限 |
writes_starved | 2 | 読み取り処理の優先度 |
fifo_batch | 16 | 1回のバッチに纏めるリクエスト数 |
front_merges | 1 | フロントマージ処理の有効化(1)/無効化(0) |
write_expire,read_expire
Deadlineスケジューラの所以である、リクエストの処理期限を表す。
この数値(milliseconds)を超えたリクエストは優先的に処理される。 デフォルト値でわかるように同期処理されるReadの方が優先度が高くなっている。
デフォルト値:(read_expire) 500ms / (write_expire) 5000ms
writes_starved
この数値を上げるとWriteに帯するReadの優先度が上がる。
デフォルト値:2
の場合は2回のRead方向に対して1回のWrite方向になります。
ここで設定された方向(Read or Write)で、複数のI/Oリクエストが一つの纏まりとして処理されることになるので注意が必要です。
イメージ図
RRRRR->RRRRR->WWWWW->RRRRR->RRRRR->WWWWW
纏められるリクエストの数は後述の fifo_batch
で設定されます。
ソースコード該当部分
linux/block/deadline-iosched.c
if (reads) { BUG_ON(RB_EMPTY_ROOT(&dd->sort_list[READ])); if (writes && (dd->starved++ >= dd->writes_starved)) goto dispatch_writes; data_dir = READ; goto dispatch_find_request; } /* * there are either no reads or writes have been starved */ if (writes) { dispatch_writes: BUG_ON(RB_EMPTY_ROOT(&dd->sort_list[WRITE])); dd->starved = 0; data_dir = WRITE; goto dispatch_find_request; }
fifo_batch
ReadまたはWrite方向のリクエストをこの数分で纏めてディスパッチします。
デフォルト値:16
デフォルトでは16リクエストを、一つに纏めてディスパッチ処理することになります。
注意点としてDeadlineスケジューラの売りの一つである write_expire
や read_expire
によるリクエストの処理期限判定も、纏められたディスパッチ間でしか機能しないことに注意する必要があります。以下にイメージを。
イメージ図
RRRRRRRRRRRRRRRR-<判定>-WWWWWWWWWWWWWWWW-<判定>-RR....
セクタでソートされたリストから取り出しするため、物理的に近いI/Oリクエストが纏められて処理され、スループットが上がるという考えです。HDD向けの設計です。
この数値を下げれば、それぞれのリクエストは細かい単位で処理されるようになり、判定も頻度も上がることになります。リクエストが処理されるまでの待ち時間も下がると考えられるので、レイテンシは短縮されることになります。
イメージ図
RR-<判定>-RR-<判定>-WW..
ソースコード該当部分
linux/block/deadline-iosched.c
if (rq && dd->batching < dd->fifo_batch) /* we have a next request are still entitled to batch */ goto dispatch_request; #------中略-------- dispatch_request: /* * rq is the selected appropriate request. */ dd->batching++; deadline_move_request(dd, rq); return 1; }
linux/Documentation/block/deadline-iosched.txt
ソースコード読む時のエントリ部分
Deadlineのソースコードはこのファイルになります。
linux/block/deadline-iosched.c
I/Oスケジューラはコールバックを登録していく形で実装するので、ここから読み始めるとわかりやすいです。
static struct elevator_type iosched_deadline = { .ops.sq = { .elevator_merge_fn = deadline_merge, .elevator_merged_fn = deadline_merged_request, .elevator_merge_req_fn = deadline_merged_requests, .elevator_dispatch_fn = deadline_dispatch_requests, .elevator_add_req_fn = deadline_add_request, .elevator_former_req_fn = elv_rb_former_request, .elevator_latter_req_fn = elv_rb_latter_request, .elevator_init_fn = deadline_init_queue, .elevator_exit_fn = deadline_exit_queue, },
それぞれ何の処理を表しているかの詳細はこの辺りに書いてあります。 https://github.com/torvalds/linux/blob/b78b499a67c3f77aeb6cd0b54724bc38b141255d/Documentation/block/biodoc.txt#L907-L967
SSD向けのチューニング例
他のI/Oスケジューラにも言えますが、Deadlineはシーク時間の低減を目指した設計になっています。デフォルトの設定も、HDD向けにチューニングされたものになっているので、改善の余地はあると思われます。
良くSSDの場合はnoopの方がdeadlineより早いという話を見ますが、ここまで書いてきたとおりDeadlineがHDD向けに作られていて、そのままのチューニングになっていることも一因かと思います。または仮想マシンの場合はホスト側のスケジューラに任せて、noopという考え方もあるかと思います。確かに手元の環境でDeadlineをチューニングしても結局Noopとの差は大きくなく、手っ取り早くパフォーマンス改善したいなら「SSDならNoop」という判断もありかもしれません。
しかし、シンプルに順次処理を行うNoopと比較して、ReadとWriteの優先度を調整できるというDeadlineスケジューラの特性活かすこともできます。
設定項目 | デフォルト値 | 設定値 | 理由 |
---|---|---|---|
scheduler | - | deadline | - |
front_merges | 1 | 0 | 物理的な距離を気にしないでいいのでマージを行わない(※1) |
fifo_batch | 16 | 1 | 判断タイミングを増やし、待ちを少なくしてレイテンシ短縮を図る。 |
writes_starved | 2 | 10 | Read処理の優先度を上がる(※2) |
read_expire | 500 | 50 | Read処理の優先度を上がる(※2) |
write_expire | 5000 | 10000 | Read処理の優先度を上がる(※2) |
nr_requests | 128 | 256 | Write処理がキューに溜まることを見越してキューを拡張しておく |
※1 SSDでも、ほとんどの場合はマージした方が良いと以下のなどには書かれています。しかし、手元の環境ではマージしない場合の方が安定した性能が出る環境もありました。試してみる価値はあるかもしれません。
nomerges
このパラメーターは、基本的にデバッグの助けとなるものです。ほとんどのワークロードでは、要求のマージが役に立ちます (SSD などの高速ストレージでも)。しかし、マージを無効にすることがよい場合もあります。例えば、先読みを無効にしたりランダム I/O を実行することなく、ストレージバックエンドが処理できる IOPS の数を知りたい場合などです。
※2 ReadやWriteの優先度はシステム特性によってチューニング値が大きく変わります。元々がReadに重きを置いている設定であることを知っているだけでも意味があるかもしれません。設定によっては予期しない遅延発生する場合もあるので、設定変更する場合は入念なテストをお忘れ無く。
手元のSSD環境では特に fifo_batch
の設定が様々なパターンで性能向上や安定が確認できました。
設定方法
設定は動的に変更可能です。
echo deadline >/sys/block/xvda/queue/scheduler echo 0 >/sys/block/xvda/queue/iosched/front_merges echo 1 >/sys/block/xvda/queue/iosched/fifo_batch echo 10 >/sys/block/xvda/queue/iosched/writes_starved echo 50 >/sys/block/xvda/queue/iosched/read_expire echo 300000 >/sys/block/xvda/queue/iosched/write_expire echo 256 > /sys/block/xvda/queue/nr_requests
設定反映の確認はcatで行います。
cat /sys/block/xvda/queue/scheduler cat /sys/block/xvda/queue/iosched/front_merges cat /sys/block/xvda/queue/iosched/fifo_batch cat /sys/block/xvda/queue/iosched/writes_starved cat /sys/block/xvda/queue/iosched/read_expire cat /sys/block/xvda/queue/iosched/write_expire cat /sys/block/xvda/queue/nr_requests
恒久的に設定したい場合は、カーネル引数に elevator=deadline
と渡すことでスケジューラを設定可能です。
単純に以下のような行をそのまま /etc/rc.local
に書いても良いと思います。
echo deadline >/sys/block/xvda/queue/scheduler echo 0 >/sys/block/xvda/queue/iosched/front_merges echo 1 >/sys/block/xvda/queue/iosched/fifo_batch
最後に
Deadlineを上記の内容を元にチューニングしてみると、デフォルトの設定よりはパフォーマンス出ることが確認できました。
しかし、ここまで書いておいてなのですが、今回チューニングした対象環境では最終的にはNoopを選びました。
Deadlineでテスト回数を増やしていくと、どんなチューニングしても時々大きな遅延が発生してしまうことあったためです。理由として考えられることは実際に動いているサーバが様々なM/Wを乗せている複雑な環境でWriteとReadの動きを規定しづらいところがあったことや、クラウド上の仮想マシンだったのでホスト側のスケジューラに任せた方がパフォーマンス出るということなどが考えられると思っています。
何度も書きますがパフォーマンステスト重要です。
参考文献とURL
● SSD の並列性を引き出す I/O スケジューラに関する研究
http://www.arch.cs.titech.ac.jp/a/thesis/Mthesis-2016-02-okumura.pdf I/Oスケジューラの性能を考える上でのポイントや、性能計測、ソースコードの読み方までとても参考になった。理解しやすく纏まっているので是非一読をオススメします。
● Redhatの情報
● 公式Doc
GitHub - torvalds/linux: Linux kernel source tree
この辺りは特に参考になりました。
linux/Documentation/block/biodoc.txt
の 4. The I/O scheduler
の項目。
「ソースコードの読み方」の項にも書きましたが、 4.1. I/O scheduler API
はコードリーディングの起点になります。
4. The I/O scheduler 4.2 Request flows seen by I/O schedulers 4.3 I/O scheduler implementation 4.4 I/O contexts
こっちはDeadlineの説明 linux/Documentation/block/deadline-iosched.txt
● 詳解Linuxカーネル
当然こちらも参考にしました。
14章ブロック型デバイスイスドライバの項に、構造体の詳細や、処理の進み方が示されていて、コード読む時の参考になります。
- 作者: Daniel P. Bovet,Marco Cesati,高橋浩和,杉田由美子,清水正明,高杉昌督,平松雅巳,安井隆宏
- 出版社/メーカー: オライリー・ジャパン
- 発売日: 2007/02/26
- メディア: 大型本
- 購入: 9人 クリック: 269回
- この商品を含むブログ (71件) を見る