ローカルディスクや組み込みデータベース(例: RocksDB)を内部状態の管理に使用するストリーム処理システムは、もはや現代のクラウドインフラに適しません。特にスケールアウトやクラウド環境では、安定した運用が難しくなります。
RocksDBをクラウドで利用しようと、多くの試みが行われてきました。しかしRocksDBはローカルストレージ、インスタンス密結合、単一テナント向けに設計されたものであり、クラウドネイティブ環境には根本的にフィットしません。
そこで私たちは発想を転換し、S3をクラウドの共通基盤と捉え、それを前提としたシステム設計に踏み切りました。S3をプライマリストレージとして採用したクラウドネイティブなストリーミングシステムを構築したのです。バックアップ用途でもオプションでもなく、基盤そのものです。ローカルディスクやRocksDBは一切使いません。
RisingWaveは、Rust製の高性能ストリーミングデータベースです。PostgreSQL互換であり、標準SQLで高度なストリーム処理ロジックを記述できます。新しいDSLや専用フレームワークを学ぶ必要はありません。
これを実現するため、私たちは状態管理レイヤー全体を再構築しました。RisingWaveはS3を直接利用しながら、高い同時実行性、低レイテンシ、マルチテナンシー、弾力的スケーリングをサポートする設計になっています。ローカル状態に依存せず、重負荷下でもリアルタイムかつ堅牢に動作させる挑戦を、私たちは見事に成功させました。
RocksDBベースシステムがクラウドでスケールしない理由
多くのストリーム処理システムは今もローカルディスクやRocksDBを状態管理に利用しています。このモデルは単純で単一テナント環境では機能します。たとえばApache FlinkはデフォルトでRocksDBを状態バックエンドとして採用し、状態はローカルディスクに保持、定期的にチェックポイントを外部ストレージへ書き出します。
しかしこのアーキテクチャはスケールしません。マルチテナンシー、AZ間冗長性、弾力的スケーリング、複雑なクエリ、状態の分離が必要になるとローカルディスクがボトルネックになります。各ノードの状態がそのディスクに紐づいているため、スケールアウト時に状態移行が必要です。フェイルオーバー時は状態再構築が必要になります。ノード障害時はディスク再マウントか状態全再ロード——脆弱かつ運用コストも高いです。
さらにRocksDBはコンパクションを計算ノードで行います。これがCPUとI/Oを圧迫し、レイテンシスパイク、ジッター、バックプレッシャー、場合によってはシステム不安定につながります。ジョイン、集約、ウィンドウ処理を含むストリーム処理では特に深刻です。
根本原因はRocksDBそのものではなく、RocksDBがクラウドネイティブなストリーム処理向けに設計されていないことです。ローカルディスク前提、インスタンスライフサイクルと状態が密結合、リモートコンパクションやオブジェクトストレージ未対応——現代クラウド環境には適しません。
S3を選んだ理由:速さよりも信頼性
私たちはS3を唯一の永続ストレージと位置づけました。セキュアでAZ間冗長性があり、ほぼ無限のスケーラビリティ、セットアップ不要——すべてのクラウドで利用可能です。
S3の強みはスピードではなくシンプルさと信頼性です。ディスク接続やスケジューリング、フェイルオーバー、インスタンスローカル状態管理は不要。S3が永続データを保持し、計算とストレージを自然に分離できます。
ただしS3には欠点もあります。平均レイテンシは問題ありませんが、テイルレイテンシは予測不能で200〜300ms超えもあります。ストリーム処理には致命的です。さらにS3はリクエスト単位課金で、状態読み書きが頻繁な場合コスト増になります。実際、計算コストよりS3リクエストコストが高くなるケースも確認しています。
結論:S3には書き込むが、クエリ時には読み込まない。 S3は耐久層であり、クエリパスには使わない。そのため私たちはインメモリキャッシュ、ローカルディスクキャッシュ、S3という3層アーキテクチャを採用しています。
Hummock:RocksDBに依存しない設計
RocksDBの限界にパッチを当てるのではなく、一から設計し直しました。Hummockという新しい状態エンジンです。
Hummockは、RisingWaveにおける状態管理用のS3ベースストレージエンジンです。
HummockはLSMツリーをベースに、インメモリキャッシュ、ディスクキャッシュ、オブジェクトストレージという3層構成で設計されています。書き込みは追記専用、各バリアチェックポイントで新しいスナップショットを生成しマルチバージョン分離を実現。クエリは常に最新スナップショットを参照し、読み書き競合がありません。
状態は不変なSST(Sorted String Table)形式で保存し、S3にアップロードします。メタデータレイヤーがインデックスやコンパクションを管理します。
パフォーマンス維持のため、Hummockはローカルディスクキャッシュを積極活用します。クエリ時には必ずキャッシュ経由で、S3読み込みは発生しません。SSTはS3アップロード後もローカル保持します。
最大の特徴はネイティブな分散設計です。状態シャッフルなしの水平スケーリング、高速リカバリ、リモートコンパクションによる計算とストレージ分離——最初からクラウド前提で作られています。
リモートコンパクション:クエリパスをクリーンに
RocksDBはクエリノード上でコンパクションを行い、リソース競合を招きます。OLTPなら許容範囲でも、ストリーム処理では低く一貫したレイテンシが必須です。
RisingWaveはコンパクションをリモートノードにオフロードします。計算ノードは読み書きだけを担当し、専用コンパクターノードがS3からデータを取得しバックグラウンドでコンパクションを実行します。
RisingWave Cloudではサーバーレスかつ弾力的な共有コンパクションプールを採用し、自動スケーリング・アイドルシャットダウンが行われます。セルフマネージド環境では専用コンパクターノードも設定可能です。
なぜEBSをデフォルトとし、NVMeより優先するのか
Hummockはウォーム状態保持のためディスクキャッシュを使います。
選択肢はNVMeローカルディスクとAWS io2 EBS。NVMeは低レイテンシ高スループットですが、容量固定、インスタンス終了時データ消失、サポート対象が限られるという制約があります。
EBSは数値上遅めですが、スケーリング容易、AZまたぎ利用可能、多くのインスタンスタイプで利用可能、そしてio2ならIOPSやテイルレイテンシも十分。だからデフォルトでEBSを選びます。
- 多くのインスタンスタイプがNVMe未対応
- NVMe容量固定
- ローカルディスクはエフェメラル
- EBSはクラウド間標準化が容易
- io2 EBSはキャッシュ用途に安定した性能を提供
Foyer:ディスクキャッシュマネジメント
効果的なディスクキャッシュ管理のため、Foyerという専用キャッシュマネージャーを開発しました。
Foyerは各コンピュートノードで動作し、すべてのディスクI/O、エビクション管理、ホット・コールドデータ追跡、リアルタイムヒット率モニタリングを担当します。
目的は明確:S3をクエリパスから排除すること。 クエリはまずインメモリキャッシュを確認し、次にFoyer管理のディスクキャッシュを参照。S3は必要最低限しかアクセスしません。
FoyerはHummockと深く統合され、クエリDAG理解、ホット・アーカイブ対象状態の自動識別、優先順位付けが可能です。
この「計算・ディスクキャッシュ・オブジェクトストレージ」の責務分離が、RisingWaveの低レイテンシかつ高信頼性スケールアウトを支えています。
結論
私たちはS3性能最適化ではなく、クエリパスからS3を外すことを目的としています。
- ホットデータはメモリ内
- ウォームデータはEBSやNVMeディスク——Foyer管理
- コールドデータはS3——コンパクションやリカバリ時のみ使用
書き込みは追記専用。クエリはスナップショット分離。コンパクションはリモート非同期。キャッシュシステムは必要なデータを賢く保持します。
これこそがクラウドネイティブなストリーム処理の理想形です:一貫したレイテンシ、計算とストレージのクリーン分離、ハック不要の水平スケーリング。
サブ100msレイテンシは目標ではなく、デフォルトです。