🔍

[翻訳] OpenSearch における階層型キャッシュ

に公開

本記事は OpenSearch Project Blog "Tiered caching in OpenSearch" の日本語訳です。

はじめに

OpenSearch のようなパフォーマンス重視のアプリケーションにとって、キャッシュは不可欠な最適化手段です。キャッシュはデータを保存することで、将来のリクエストをより速く処理し、クエリの応答時間とアプリケーションのパフォーマンスを向上させます。OpenSearch は主にリクエストキャッシュとクエリキャッシュの 2 種類のキャッシュを使用しています。どちらもオンヒープキャッシュであり、そのサイズはノード上で利用可能なヒープメモリの量によって決まります。

オンヒープキャッシュ:良いスタートだが、十分か?

OpenSearch におけるオンヒープキャッシュは、データをノードにローカルでキャッシュする迅速、シンプル、かつ効率的な方法を提供します。低レイテンシーのデータ取得を実現し、大幅なパフォーマンス向上をもたらします。しかし、これらの利点にはトレードオフがあり、特にキャッシュが容量に近づくと問題が生じます。キャッシュサイズが容量に近づくと、多数の退避(eviction)とミスが発生し、パフォーマンス上の課題につながる可能性があります。

オンヒープキャッシュのサイズは、ノードで利用可能なヒープメモリの量に直接関連しており、これは有限でコストがかかります。この制限により、大規模なデータセットを保存したり、多数のクエリを管理したりする際に課題が生じます。キャッシュが容量に達すると、新しいクエリのためのスペースを確保するために、古いクエリを退避させる必要があります。この頻繁な退避はキャッシュのチャーンを引き起こし、退避されたクエリが後で再計算される必要があるため、パフォーマンスに悪影響を与える可能性があります。

より良い方法はあるか?

前述のように、オンヒープキャッシュは大規模なデータセットを管理する際に制限があります。より効果的なキャッシュメカニズムは階層型キャッシュであり、これは複数のキャッシュ層を使用し、オンヒープキャッシュから始まりディスクベースの階層まで拡張します。このアプローチはパフォーマンスと容量のバランスを取り、貴重なヒープメモリを消費することなく、より大きなデータセットを保存できるようにします。

過去には、従来の回転式ハードドライブが遅かったため、ディスクをキャッシュに使用することに懸念がありました。しかし、現代の SSD や NVMe ドライブなどのストレージ技術の進歩により、はるかに高速なパフォーマンスが実現されています。ディスクアクセスはまだメモリよりも遅いですが、速度差は十分に狭まっており、パフォーマンスのトレードオフは最小限であり、多くの場合、ストレージ容量の増加による利点によって相殺されます。

階層型キャッシュの仕組み

階層型キャッシュは、パフォーマンスとサイズによって積み重ねられた複数のキャッシュ層を組み合わせます。例えば、第 1 階層はオンヒープキャッシュで、最もパフォーマンスが高いがサイズは小さいです。第 2 階層はディスクベースのキャッシュで、速度は遅いが大幅に多くのストレージを提供します。以下の画像は階層型キャッシュモデルを示しています。

OpenSearch は現在、階層型キャッシュモデルでオンヒープ階層とディスク階層を使用しています。アイテムがオンヒープキャッシュから退避されると、それはディスクキャッシュに移動します。各受信クエリに対して、OpenSearch はまずデータがオンヒープキャッシュまたはディスクキャッシュのいずれかに存在するかどうかを確認します。見つかった場合、応答はすぐに返されます。見つからない場合、クエリは再計算され、結果はオンヒープキャッシュに保存されます。以下の図はキャッシュアルゴリズムを示しています。

現在、OpenSearch はリクエストキャッシュに対してのみ階層型キャッシュモデルをサポートしています。デフォルトでは、リクエストキャッシュはオンヒープキャッシュ階層を使用します。キャッシュサイズは設定可能であり、デフォルトではノード上のヒープメモリの 1% です。階層型キャッシュを有効にすると、メモリに収まらない大きなデータセットを保存するディスクベースのキャッシュ階層が追加されます。これによりオンヒープキャッシュの負荷が軽減され、全体的なパフォーマンスが向上します。

階層型キャッシュはプラガブルな設計です。階層型キャッシュ設定を使用して、異なるタイプのオンヒープキャッシュとディスクキャッシュの実装やライブラリをシームレスに統合できます。詳細については、階層型キャッシュをご覧ください。

階層型キャッシュを使用するタイミング

階層型キャッシュは現在リクエストキャッシュにのみ適用されるため、既存のオンヒープリクエストキャッシュがデータセットを保存するのに十分な大きさでなく、頻繁な退避が発生する場合に役立ちます。GET /_nodes/stats/indices/request_cache エンドポイントを使用してリクエストキャッシュの統計を確認し、退避、ヒット、ミスを監視できます。頻繁な退避といくつかのヒットが見られる場合、階層型キャッシュを有効にすることで大幅なパフォーマンス向上が期待できます。

階層型キャッシュは特に以下の状況で有益です:

  • ドメインで多くのキャッシュ退避と繰り返しクエリが発生している。これはリクエストキャッシュ統計を使用して確認できます。
  • ログ分析や読み取り専用インデックスなど、データが頻繁に変更されず、頻繁な退避が発生している場合。

デフォルトでは、リクエストキャッシュは集計クエリの結果のみを保存します。?request_cache=true クエリパラメータを使用して、特定のリクエストのキャッシュを有効にできます。

階層型キャッシュの有効化方法

階層型キャッシュを有効にするには、ノード設定を構成する必要があります。これには、ディスクキャッシュプラグインのインストール、階層型キャッシュの有効化、および必要に応じて他の設定の調整が含まれます。詳細な手順については、階層型キャッシュのドキュメントをご覧ください。

パフォーマンス結果

この機能は現在実験的であり、本番環境での使用は推奨されていません。そのパフォーマンスを評価するために、いくつかのテストを実施しました。

パフォーマンステストでは、様々なクエリタイプとキャッシュヒット率において、階層型キャッシュとデフォルトのオンヒープキャッシュを比較しました。また、異なるレイテンシーパーセンタイル (p25, p50, p75, p90, p99) も測定しました。

クラスターセットアップ

  • インスタンスタイプ: c5.4xl
  • ノード数: 1
  • 合計ヒープサイズ: 16 GB
  • デフォルトキャッシュ設定: オンヒープキャッシュサイズ: 40 MB
  • 階層型キャッシュ設定:
    • オンヒープキャッシュサイズ: 40 MB
    • ディスクキャッシュサイズ: 1 GB

OpenSearch Benchmark の nyc_taxis ワークロードを使用しましたが、統計的に再現可能なクエリを発行するためのサポートを追加する必要がありました。元のベンチマークは常にキャッシュを無効にして実行されるため、クエリの繰り返しのバリエーションを許可しません。このサポートを追加することで、実際のユースケースをより適切にシミュレートし、目標のキャッシュヒット率をテストし、クエリの繰り返しの変動を考慮することができました。

ワークロードは、シャードレベルのレイテンシーによって分類されたクエリの混合で構成されていました:

  • 高コスト: >150 ms
  • 中程度: 10–150 ms
  • 低コスト: <10 ms

以下の図はパフォーマンステスト結果を示しています。赤い垂直線はベースラインのパーセンタイルを示し、デフォルトのオンヒープキャッシュが有効で階層型キャッシュが無効の状態です。0%、30%、70% のクエリ再現性でテストを行い、これらは異なるキャッシュヒット率に対応しています。

初期結果は、階層型キャッシュが特に高いキャッシュヒット率と p75 未満のレイテンシーで良好に機能することを示しています。特に計算コストの高いクエリを実行する場合、階層型キャッシュはそれらを再計算する必要性を減らし、代わりにキャッシュから直接結果を取得するため、利点が顕著です。

今後の展望

階層型キャッシュは有望な機能ですが、さらなる改善に積極的に取り組んでいます。現在、階層型キャッシュをより高性能にする方法を模索しています。将来の強化には、頻繁にアクセスされるアイテムをディスクキャッシュからオンヒープキャッシュに昇格させること、再起動間でディスクキャッシュデータを永続化すること、クエリキャッシュなどの他の OpenSearch キャッシュタイプと階層型キャッシュを統合することなどが含まれる可能性があります。この Issue で進捗状況を確認できます。非本番環境で階層型キャッシュを試し、この機能の改善に役立つフィードバックを共有することをお勧めします。

Discussion