cgroup v2 io cost model
全く気づいてなかった。4.19 ごろから? 5.4 だ。
- https://facebookmicrosites.github.io/resctl-demo-website/docs/demo_docs/setting_benchmarks/iocost/
- https://lwn.net/Articles/793460/
- https://lwn.net/Articles/792256 (the io.weight name is no longer used だそうだ)
- https://partners-intl.aliyun.com/help/en/doc-detail/155863.htm
- https://facebookmicrosites.github.io/cgroup2/docs/io-controller.html
- https://linuxfoundation.org/wp-content/uploads/resctl-demo-lf-mentorship.pdf (関係あるかわからん)
- https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/Documentation/admin-guide/cgroup-v2.rst?h=v5.17-rc7&id=7caa47151ab2e644dd221f741ec7578d9532c9a3
- https://kernelnewbies.org/Linux_5.4#More_accurate_cgroup_I.2FO_control_with_blk-iocost
- IOCost: Block IO Control for Containers in Datacenters 論文っぽい(Tejunさん)
IO コストパラメーター
要約
iocost コントローラーは IO ごとのコストを見積もるのに IO コストモデルを使います。そして、見積もったコストにもとづいて仕事量を調節する比例制御を実装します。各IOはシーケンシャルかランダムかに分類され、それに応じて基本コストが与えられます。その上で、IOの長さに比例したサイズコストが追加されます。このモデルは単純ではありますが、様々な機器の動作特性を十分に捉えています。
IO制御とio.costコントローラのハイレベルな説明については、IO制御のページを参照してください。
パラメーター
カーネルにはいくつかデフォルトパラメーターがありますが、妥当なレベルでの制御を実現するには、特定のデバイスに応じて /sys/fs/cgroup/io.cost.model
で IO コストモデルを設定してください:
- rbps - 最大シーケンシャルリードBPS
- rseqiops - 最大4kシーケンシャルリードIOPS
- rrandiops - 最大4kランダムリードIOPS。
- wbps - 最大シーケンシャルライトBPS
- wseqiops - 最大4kシーケンシャルライトIOPS
- wrandiops - 最大4kランダム書き込みIOPS
もちろん、コストモデルは現実の近似値です。 ハードウェアがどのように動作するかを正確に予測することはできません。特に、デバイス自体が時間の経過とともに動的なパフォーマンスの偏差を示すためです。 コントローラーは、Quality-of-Service (QoS) パラメーター (レイテンシーのターゲットと vrate の境界) に従って合計コマンド発行率をスケーリングすることにより、状況に適応します。 次のパラメーターは、/sys/fs/cgroup/io.cost.qos
で構成されます。
- rpct - 使用する読み込みレイテンシーのパーセンタイル
- rlat - 読み込みのターゲットレイテンシー
- wpct - 使用する書き込みレイテンシーのパーセンタイル
- wlat - 書き込みのターゲットレイテンシー
- min - vrate 境界最小値
- max - vrate 境界最大値
レイテンシターゲットは、コントローラがデバイスが完全に飽和したとみなすタイミングを決定します。例えば、rpct=95、rlat=5000は、リード完了レイテンシの95パーセンタイルが5msを超える場合、デバイスはフル稼働状態であり、コマンド発行はスロットルされるべきであることを意味します。
Quality-of-Service (QoS) パラメーターである vrate bounds は、遅延の目標を達成するためにデバイスをどれだけ調整できるかのパーセンテージ範囲を表します。 たとえば、50% から 125% の範囲を指定すると、コスト モデル パラメーターに従って合計 100% の半分から 1.25 倍の間で最大コマンド発行レートを調整するようコントローラーに指示します。 rbps が 400MBps で、ワークロードがシーケンシャル読み取りのみを実行している場合、完了の待ち時間に応じて、iocost コントローラーは 200MBps から 500MBps の間で発行を許可します。
QoSパラメータは、デバイスそのものと、それほどではありませんが、ワークロードの要求の両方から影響を受けます。ほとんどの場合、デバイスのレイテンシ応答グラフには、レイテンシが急増するポイントがあります。デバイスはすでに飽和状態にあり、同時実行のコマンドを増やすとレイテンシが増加します。そのポイントを中心にターゲットレイテンシーを設定することが、QoSパラメータを構成する1つの方法です。
もう一つの興味深い点は、vrateの範囲が基礎となるデバイスをガイドすることができることです。例えば、SSDの中には、短時間に非常に高速で大量の書き込みを完了した後、半昏睡状態に陥り、数百または数千ミリ秒の間、他のコマンドを完了できないものがあります。このようなバーストは、単純な短時間のベンチマークではよく見えるかもしれませんが、実用上のメリットはあまりなく、レイテンシに敏感なワークロードにとっては有害で、次のストールによって打撃を受けることになるかもしれません。また、ガベージコレクションのある段階において、どんなに少ない IO を投げても、しばらくの間、レイテンシーが著しく上昇する SSD があります。このような場合、コマンド発行率をさらに下げても、仕事の総量が減るだけで何も得られない。vrate 最小境界値(min bound)は、そのような一時的な極端なケースから保護することができます。
これらは設定する数字がたくさんあります。しかしほとんどの場合、デバイスのモデル固有です。将来的には、既知のデバイスとそのパラメーターを含む出たーベースを構築し、自動的に設定されるようにしたいと考えています。
ベンチマーク
/var/lib/resctl-demo/misc-bin/iocost_coef_gen.py
を rd-bench-iocost.service として動作させ、コストモデルと QoS パラメーターの両方を定義します。
QoS パラメーターは 90% 負荷時のランダム IO が完了するレイテンシーの 4 倍として計算されます。そして、vrate の範囲は 25% から 90% の間です。この計算式は、さまざまなデバイスで信頼性の高いデモ動作を実現するために経験的に導き出されたもので、他のユースケースで最適とは限りません。
ベンチマークが完了すると、デモは結果を /var/lib/resctl-demo/bench.json
に記録し、/sys/fs/cgroup/io.cost.model
と /sys/fs/cgroup/io.cost.qos
に伝搬させます。そのファイルを編集すると、デモはそれに応じてカーネル設定を更新します。
"Toggle iocost benchmark" ボタンをクリックすると、hashd ベンチマークを再実行したり、キャンセルしたりできます。
IOコントロール
包括的なリソース制御を実現するためには、IO容量の配分を制御することが重要である。この依存性は、ファイルシステムやRaw IOを直接実行するワークロードでは明らかですが、メモリ管理とIOが絡み合っているため、特にメモリが不足すると、どのワークロードもIO依存になり得ます。
すべてのバイナリとライブラリはファイルシステム上に存在し、オンデマンドでロードされ、動的に管理されます。アプリケーションが新しいコードパスの実行を開始すると、基礎となるデバイスからの読み込みを待つことになります。わずかでもメモリの競合があれば、通常のメモリ管理の一環としてページが回収され、フォルトバックされる。優先順位の低いグループからのIOがIOデバイスを飽和させると、優先順位の高いグループは、そのような読み取りやページフォルトでストールすることになります。
このようなことが起こる可能性は、他にもたくさんあります。もう一つの例は、ファイルシステムのメタデータ書き込みの共有です。ほとんどのファイルシステムには、ジャーナルやトランザクションコミットなど、システム内の複数のエンティティが待機する必要がある共有操作があります。cgroup がデバイスに殺到して、これらの共有メタデータ IO が大幅に遅くなると、ファイルシステムの更新を行おうとするシステム上のすべてのものが、どんなに小さくても、相対的な優先順位に関係なく、ストールされることになります。上記のように書き込みがシステム全体で滞ると、システムが微妙な間接依存の連鎖を露呈し、一見するとIOに依存していないように見えるアプリケーションに影響を与えることも珍しくありません。IOが制御されないと、メモリやその他のリソースがどんなに保護されていても、リソース保護が破綻してしまう。
IOコストコントローラー
CPUやメモリでは,クロック時間やバイト数が十分に正確な近似値として機能するのに対し,IOリソース制御の課題の1つは,些細なことで観測可能なコスト指標を持たないことである.
IOデバイスでは、帯域幅とiopsが最もよく使われる指標ですが、デバイスやIOパターンが異なると、数桁の差が生じやすく、IO容量分配には使えません。クラッチの多いオンデバイスタイムは、キューイングされていないローテーションデバイスでは有用な近似値として機能しますが、回転式のものであっても、最新のデバイスではもはや通用しないのです。
些細なことで観測できるコスト指標はないものの、完全な謎というわけでもない。例えば、回転式デバイスでは、シークコストが支配的で、連続転送はサイズに比例して寄与する量が少ない。少なくとも、これらの異なるタイプのIOの相対的なコストを特徴付けることができれば、合理的な仕事保存型の比例IOリソース分配を実装することができるはずです。
iocostコントローラは、IOコストモデルを採用して各IOのコストを推定することにより、この問題を解決する。各IOは、シーケンシャルかランダムかに分類され、それに応じて基本コストが与えられます。その上で、IOの長さに比例したサイズコストが追加されます。このモデルはシンプルながら、多種多様なデバイスの動作特性を十分に捉えています。
キューを所有する
一連の書き込みが行われると、多くのSSDはキューに入れられ、維持できる速度よりもはるかに速く完了し、その後劇的に速度が低下する。一部のデバイスでは、数十メガバイトの書き込みを1分間維持した後に、読み取り完了待ち時間の中央値が数秒に上昇することがあります。このようなバースト的な動作は、マイクロベンチマークではよく見えるかもしれませんが、それでは何の価値もありません。システム全体としては、書き込みのバッファリングでもっと良い仕事ができますし、読み込みリクエストに数百ミリ秒かかるストレージデバイス上で動作するレイテンシに敏感なワークロードは、応答性とレイテンシの一貫性を維持することはできません。
多くのNVMEデバイスは、何倍も深いコマンドキューを持ちながら、ミドルレンジのSATAデバイスよりも性能が高いわけではありません。深いキューは、書き込みキューによる問題を悪化させ、読み取りコマンドも同様の問題に悩まされることになります。ネットワークのQoSと同様に、キューを所有することなくレイテンシーQoSを実装することはできません。IOのレイテンシをコントロールしたいのであれば、コントロールポイントは、IOの流れの中の流れが詰まるポイント(choking point)でなければならず、ハードウェアのキューでブロックされる量を変えるだけでなく、スロットルで上下に動かしてレイテンシに直接影響を与えるようにする必要があります。
コストモデルを通じて、iocostコントローラは、デバイスが1秒間にできるIOの量を理解し、それに応じて総IOレートをペース配分して制限することができます。
IO制御とファイルシステム
ファイルが読み書きされるとき、ストレージデバイスに到達する前に、メモリ管理、ファイルシステム、IOレイヤーの高いスタックを通過する必要があります。スタックのどこかに優先順位の逆転があり、優先順位の低いcgroupが優先順位の高いものをブロックしてしまうと、IO制御、ひいてはリソース制御が破綻してしまう。
最近のファイルシステムは、オペレーションが複雑に絡み合っていることが多く、発行者ベースのストレートな制御は不十分である。例えば、優先度の低いcgroupからのメタデータ更新をやみくもにスロットルダウンすると、優先度の高いcgroupからの他のメタデータ更新が、ファイルシステム内部の制約により後ろでブロックされる可能性があります。
このような状況を回避するために、ファイルシステムは、状況に応じて異なる制御戦略を判断して適用するように更新する必要があります。依存関係のないデータの書き込みは、直接制御することができます。優先順位の逆転を引き起こす可能性のあるメタデータの更新は、誰が引き起こしたかにかかわらず、すぐに実行されなければならない。しかし、発行元のcgroupにバックチャージすることで、時間の経過とともに帳尻を合わせたい。
現在、IO制御を完全にサポートしている最新のファイルシステムはbtrfsだけです。ジャーナリングなしのext2も機能しますが、現時点ではほとんどのアプリケーションで適切でない可能性があります。これらの優先順位の逆転の影響は、あなたのシステムでIOがどの程度ボトルネックになっているかによって異なります。
実際に動かしてみよう
rd-hashdはすでに全負荷で動作しているはずです。メモリフットプリントがマシンの大部分を埋め尽くしてウォームアップしたら、Disable IO control and start the memory and IO hogs ボタンをクリックして、IOコントロールを無効にしてメモリホッグとIOホッグを1つずつ開始しましょう。メモリホッグはIO分離テストに効果的なストレス要因です。なぜなら、スワップ書き込みが大量に発生し、システムの他の部分がメモリを奪い合い、再利用IOに頼らざるを得ないからです。ランダムリードIOを爆発させるIOホッグと組み合わせると、ハイエンドのエンタープライズSSDでさえも圧倒することができます。
警告
このシステムはIO保護なしで動作しているため、システムの応答性を保証することはできません。このデモプログラムも含め、すべての動作が遅くなり、完全に停止する可能性があります。
rd-hashdが苦戦したら、メモリとIOホッグを停止し、Stop the memory and IO hogs and restore IO controlボタンをクリックしてIO保護をオンに戻してください。
sysloadカウントがゼロになり、rd-hashdのRPSとメモリ使用量が安定するのを待ってから、Start the memory and IO hogsボタンをクリックして、同じメモリとIOホグを再び起動します。
カーネルはhashdを無限に保護することができます。OOMDはいずれ介入してきます。
IO コントローラー
異なるニーズを持つワークロードがシステム上のリソースをシェアするとき、各ワークロードの IO 操作を制御、制限、優先順位付けできることが重要です。
例えば、バックグラウンドのアプリが過剰に IO を使い始めても、メインのワークロードに影響がないようにする必要があります。また、優先度の低いワークロードに対しては IO を制限し、一方で優先度の高いワークロードには IO を提供するという柔軟性がシステムには備わっていることを確認する必要があります。
cgroup2 IO コントローラーは、IO リソースの分配を制御し、cgroup が読み取りまたは書き込みできる 1 秒あたりの IO 操作数(IOPS)を指定できます。また、cgroup の IO 使用量と IO プレッシャー を測定、監視できます。
IO cost model based work-conserving porportional controller
Changes from v1[1]:
- Prerequisite patchsets had cosmetic changes and merged. Refreshed
on top. - Renamed from ioweight to iocost. All source code and tools are
updated accordingly. Control knobs io.weight.qos and
io.weight.cost_model are renamed to io.cost.qos and io.cost.model
respectively. This is a more fitting name which won't become a
misnomer when, for example, cost based io.max is added. - Various bug fixes and improvements. A few bugs were discovered
while testing against high-iops nvme device. Auto parameter
selection improved and verified across different classes of SSDs. - Dropped bpf iocost support for now.
- Added coef generation script.
- Verified on high-iops nvme device. Result is included below.
IOリソースを制御する際の課題のひとつは、簡単に観測できるコストメトリックの欠如です。これは、実時間とバイト数が十分に正確な近似として機能する CPU やメモリとは異なります。
帯域幅とiopsは、IOデバイスの最も一般的な指標ですが、デバイスの種類や仕様によっては、異なるIOパターンで数桁の差が生じやすく、IO能力の分配の目的には役に立ちません。多くのクラッチを持つオンデバイスの時間は、非キューの回転式デバイスでは有用な近似値として機能しますが、最新のデバイスでは、回転式のものでさえ、これはもはや実行不可能です。
私たちが気軽に観察できるコスト指標はありませんが、完全な謎というわけではありません。 例えば、回転するデバイスでは、シークコストが支配的であり、連続転送はサイズに比例して負担が小さくなる。 少なくとも、これらの異なるタイプのIOの相対的なコストを特徴付けることができれば、合理的な作業効率の良い比例IOリソース配分を実施することができるはずです。