このブログは、siddontangの"How We Optimize RocksDB in TiKV — Smarter Flow Control"の抄訳です。翻訳はGeminiの翻訳をベースに、@bohnenが担当しました。
TiKVが長年にわたって成長する中で、本番環境のクラスタで最も根強く見られた問題の一つが「書き込みストール(Write Stall)」でした。
システムがスムーズに動作しているときもあれば、突然不安定になることもありました。
詳しく調べてみると、これらの問題の多くは RocksDBのフロー制御と書き込みストールのメカニズム に起因していることがわかります。
RocksDBは自身を保護するように設計されています。
LSMツリーが過負荷状態(L0ファイルが多すぎる、保留中のコンパクションが多すぎる、Memtableが積み重なるなど)になると、単純に書き込みを停止(ストール)させます。
これはデータの整合性にとっては良いことですが、TiKVのような分散トランザクションシステムにとっては良くありません。
ひとつのRocksDBインスタンスでの書き込みストールの影響は、すぐに広がってしまいます。
- コミットレイテンシが増加する
- 上流のTiDBトランザクションレイテンシが増加する
- クラスタ全体が不安定になる
そこで私たちは考え方を変えました。
RocksDBが土壇場でストールするのをただ待つのではなく、ストールが発生する前に、TiKVが(書き込みの)圧力を予測して平準化できないだろうか? と。
これが、数年にわたるRocksDBとTiKV内部のフロー制御をリプレースし、強化し、再設計するための取り組みの始まりでした。
この記事では、主な3つの改善点について説明します。
1. 書き込み増幅に基づくレート制限
PR: https://github.com/tikv/rocksdb/pull/368
RocksDBのデフォルトのレートリミッターは単純です。
I/Oが高くなりすぎたら、書き込みスループットを制限する。
しかし、これは事後的な対応であり、プロアクティブではありません。
TiKVのワークロードはバースト(突発)的に発生する傾向があります。
- 大量の書き込み → 多数のL0ファイル
- 多数のL0ファイル → 至急コンパクションが必要
- 急なコンパクション → バックグラウンドI/Oの増加
デフォルトのリミッターが反応する頃には、RocksDBはすでに書き込み圧力を受けており、書き込みストールは避けられなくなっています。
私たちの改善策
私たちは「書き込み増幅(Write Amplification)」を考慮したレートリミッターを導入しました。
これは以下のようなシグナルを監視します。
- (ストレージへの)フラッシュのスループット
- コンパクションのバックログ(未処理分)
- 書き込み増幅率
これらのヒントから、コンパクションの圧力がいつ高まるかを予測します。
フラッシュI/Oが急増すれば、コンパクションI/Oがすぐに発生することがわかります。
その場合、レートリミッターはI/Oのスパイク(急上昇)を防ぐために、事前に書き込みを十分に減速させます。
結果
- 書き込みストールの減少
- コンパクションフローの円滑化
- 書き込みレイテンシの安定化
事態が悪化してから反応するのではなく、悪化する前に行動するのです。
2. TiKVのI/Oレートリミッター : すべてのI/Oを検査する
PR: https://github.com/tikv/rocksdb/pull/383
RocksDBのレートリミッターはRocksDBのことしか知りません。
しかし、TiKVにはシステム全体の視点が必要です。
TiKVは以下を実行します。
- Raftログの追記(アペンド)
- ステートマシンの適用
- スナップショットの生成
- RocksDBへの書き込み
- コンパクション
- ファイルの取り込み(Ingestion)
これらに優先順位をつける必要があります。
例えば:
- フォアグラウンドの書き込みとRaftログは常にスムーズに実行されるべきです
- スナップショットI/Oがディスクを圧迫してはいけません
- コンパクションは実行する必要がありますが、積極的すぎてはいけません
私たちの改善策
私たちは FileSystemInspectedEnv を追加しました。これはRocksDB内部に環境(Env)ラッパーとして存在します。
すべてのI/O操作はここを通過し、TiKVは以下を検査できます。
- どのような種類のI/Oか
- どれだけのI/Oが消費されているか
- どのサブシステムが担当しているか
これがTiKVのシステム全体のI/Oレート制限のバックボーンとなります。
結果
TiKVは、Raft、コンパクション、RocksDB書き込みの間で、統一された方法でI/Oを調整できるようになりました。
これはRocksDBのデフォルト機能だけでは不可能です。
3. RocksDBの書き込みストールをTiKVフロー制御に置き換える
PR: https://github.com/tikv/rocksdb/pull/384
RocksDBは書き込みを完全に停止させること(書き込みストール)で過負荷を制御します。
しかし、このメカニズムはTiKVにとってはあまりにも大雑把で予測不可能です。
そこで私たちは、RocksDBのストールロジックを徐々に「TiKVフロー制御」に置き換えました。これは、単一のRocksDBインスタンスだけでなく、クラスタの振る舞いに基づいて構築された、よりスムーズで段階的なスロットリング(帯域制限)メカニズムです。
関連する作業
- TiKVがタイミングを決定できるように書き込みストールを無効化
- インジェストレベルの情報(例:L0へのインジェスト vs L2へのインジェスト)を公開
- 古いコンパクションスケジューリングコード(base_background_compaction)を削除
これらの改善により、TiKVはスループットを段階的に調整できます。
- 軽いスロットリング、中程度のスロットリング、重いスロットリング
- どうしても必要な場合のみ → ストール
結果
- 書き込みパスのレイテンシが予測可能になる
- バックグラウンド作業が安定する
- スループットが極端に上下しなくなる
これは、本番環境レベルの安定性を達成するために不可欠です。
最後に
フロー制御は最も華やかなトピックではありませんが、実際のシステムにおいては、パフォーマンスの安定性のすべてを決定します。
以下の組み合わせによって:
- 予測的な、書き込み増幅ベースの制限
- システム全体のI/O検査
- そしてTiKV主導のフロー制御フレームワーク
私たちはRocksDBを、事後対応的なストレージエンジンから、分散データベース内部で予測通りに振る舞うサブシステムへと変えました。
これはユーザーが目にすることのないエンジニアリング領域の一つですが、その違いはすぐに体感できるはずです。
TiDB Xはどのようにして書き込みストールを劇的に減らすのか
書き込みストールはLSMツリー設計の本質的な副作用です。TiDB XでもLSMツリーを使用しているため、理論的には書き込みストールは依然として発生する可能性があります。
しかし、下記のような大きな違いがあります
TiDB Xはアーキテクチャを再設計し、書き込みストールの一般的な原因が実際にはほとんど発生しないようにしています。
その方法を次に説明します。
オブジェクトストレージ上でのリモートコンパクション
TiDB Xでは、SSTファイルはローカルディスクではなくオブジェクトストレージ上に存在します。
これによりすべてが変わります。
従来のRocksDBインスタンスは、フォアグラウンドの読み書きトラフィックを処理するのと同じノードでコンパクションを実行する必要がありました。
そのため、コンパクションは(フォアグラウンド処理と)CPU、メモリ、I/Oを奪い合います。これが書き込みストールの原因です。
TiDB Xでは:
- コンパクションジョブをリモートワーカーにオフロード(委譲)できます
- コンパクションはローカルI/Oではなく、オブジェクトストレージの帯域幅を消費します
- フォアグラウンドのワークロードは隔離され、スムーズなままです
これにより、書き込みストールにつながる書き込み増幅圧力の最大の原因が効果的に取り除かれます。
リージョンの全レプリカ間でのLSMツリーの共有
現在のTiKVでは、すべてのレプリカ(リーダー+フォロワー)が独立したRocksDBインスタンスを維持しています。
これはつまり:
- すべてのリージョンが3つの別々のLSMツリーのコピーを持つ
- すべてのレプリカが同じコンパクションを独立して実行する
- コンパクションの総作業量が3倍になる
- 複数のノードが独立して圧力限界に達するため、書き込みストールが発生しやすくなる
TiDB Xでは:
リージョンのすべてのレプリカは、リージョンリーダーによってコンパクションされる1つの論理LSMツリーを共有します。
フォロワーは単にその結果を利用するだけです。
これにより、コンパクションの総量が大幅に削減されます。
- 重複したコンパクション作業がない
- 書き込み増幅が低い
- 書き込みストールの閾値に達する可能性がはるかに低い
これは単なる最適化ではなく、コンパクションモデルの完全な転換です。
ホットリージョンのためのエラスティックな計算リソース
時として、書き込みストールはコンパクション圧力ではなく、突発的なホットスポットによって引き起こされます。
- あるリージョンが大量の書き込みを受ける
- Memtableが急速に埋まる
- SSTフラッシュが加速する
- コンパクション圧力が増大する
従来のTiKVノードでは、CPU、メモリ、I/Oが固定されているため、迅速に対応することができません。
しかし、TiDB Xは弾力的な計算リソース上で動作します。
リージョンがホットになったとき、TiDB Xは以下が可能です。
- リージョンをより強力なノードに即座に移行する
- より大きなMemtableのためにメモリを多く割り当てる
- キャッシュ容量を増やす
- SSTフラッシュを延期する
- ストールを引き起こすことなく、より高いスループットを維持する
弾力性(Elasticity)により、書き込みストールは「突然の危機」から「事前に回避できるもの」へと変わります。
TiDB Cloudを試す
- これらの最適化が実際のワークロードでどのように動作するかを確認してください — TiDB Cloudを無料で試す
- TiDB Cloudでビジネスを始める準備ができたら — TiDB Cloud Essential 101 にアクセス
- AIアプリの構築方法に興味があるなら — TiDB Cloud AI を発見する
参考文献
- How We Optimize RocksDB in TiKV — The Battle Against the DB Mutex
- How We Optimize RocksDB in TiKV — MVCC GC Optimization
- How We Optimize RocksDB in TiKV — SST Compaction Guard
TiDB Cloudを試す
- これらの最適化が実際のワークロードでどのように動作するかを確認してください TiDB Cloudを無料で試す
- TiDB Cloudでビジネスを始める準備ができたら — TiDB Cloud Essential 101にアクセス
- AIアプリの構築方法に興味があるなら — TiDB Cloud AIを発見する