varbit チャンクを使用する(しない)ケース

Prometheus サーバーの組み込み時系列データベース(TSDB)は、各時系列の生のサンプルデータを、一定の1024バイトサイズのチャンクに整理します。生のサンプルデータに加えて、チャンクにはいくつかのメタデータが含まれており、チャンクごとに異なるエンコーディングを選択できます。最も基本的な違いはエンコーディングバージョンです。新しく作成されるチャンクのバージョンは、コマンドラインフラグ-storage.local.chunk-encoding-versionで選択します。これまで、サポートされているバージョンは、元のデルタエンコーディング用のバージョン0と、改良されたダブルデルタエンコーディング用のバージョン1の2つだけでした。0.18.0 リリースで、ダブルデルタエンコーディングのバリエーションであるバージョン2を追加しました。これは、チャンク内のサンプルごとに可変ビット幅を使用するため、varbit エンコーディングと呼ばれています。バージョン1はほとんどすべての点でバージョン0よりも優れていますが、バージョン1と2の間にはトレードオフがあります。このブログ記事は、その決定を行うのに役立ちます。バージョン1はデフォルトのエンコーディングのままなので、この記事を読んだ後にバージョン2を試したい場合は、コマンドラインフラグで明示的に選択する必要があります。行き来しても害はありませんが、既存のチャンクは一度作成されるとエンコーディングバージョンが変更されることはありません。ただし、これらのチャンクは設定された保持時間に従って徐々に段階的に廃止され、コマンドラインフラグで指定されたエンコーディングのチャンクに置き換えられます。

varbit エンコーディングとは何か

当初から、新しいエンコーディングを簡単に追加できるように、チャンク化されたサンプルストレージを設計しました。Facebookが彼らのインメモリTSDB Gorillaに関する論文を発表したとき、独立して開発されたGorillaとPrometheusのアプローチの間に多くの類似点があり、興味を引かれました。しかし、多くの根本的な違いもあり、詳細に調査し、Prometheusを改善するためにGorillaからインスピレーションを得られないか疑問に思いました。

週末が空いたので、試してみることにしました。コーディングに没頭し、後に(かなりのテストとデバッグの後)varbit エンコーディングになるものを実装しました。

今後のブログ記事では、エンコーディングの技術的な詳細について説明します。現時点では、新しいvarbit エンコーディングと従来のダブルデルタエンコーディングのどちらを選択するかについて、いくつかの特性を知るだけで十分です。(以降、後者を単に「ダブルデルタエンコーディング」と呼びますが、varbit エンコーディングもダブルデルタを使用していることに注意してください。ただし、方法は異なります。)

varbit エンコーディングの利点は何ですか?

簡単に言うと、はるかに優れた圧縮率を提供します。ダブルデルタエンコーディングは現実世界のデータセットではサンプルあたり約3.3バイト必要ですが、varbit エンコーディングはSoundCloudの大規模な本番サーバーではサンプルあたり1.28バイトまで減少しました。これは、ディスク容量の効率が約3倍向上することを意味します(Gorillaで報告されたサンプルあたり1.37バイトよりもわずかに優れていますが、SoundCloudの典型的なデータセットはFacebookの典型的なデータセットとは異なる可能性があるため、注意が必要です)。

それでは、その意味を考えてみましょう。RAM内のサンプル数が3倍、ディスク上のサンプル数が3倍、ディスク操作が1/3になり、現在ディスク操作が取り込み速度のボトルネックになっているため、取り込み速度も3倍になります。実際、最近報告された毎秒80万サンプルという新しい取り込み記録は、varbit チャンクを使用した場合のみ可能でした(もちろんSSDを使用した場合です)。スピニングディスクを使用する場合、ボトルネックははるかに早く到達するため、3倍の利点はさらに重要になります。

これはあまりにも素晴らしすぎて本当とは思えません…

では、落とし穴はどこにあるのでしょうか?

まず、varbit エンコーディングはより複雑です。そのため、値をエンコードおよびデコードするための計算コストが多少増加し、サンプルデータを読み書きするすべてに根本的に影響します。幸いなことに、これは通常、操作の総コストのごく一部にしか寄与しないものの比例的な増加に過ぎません。

varbit エンコーディングの別の特性は、潜在的にはるかに関連性があります。varbit チャンクのサンプルは順番にしかアクセスできませんが、ダブルデルタエンコードされたチャンクのサンプルはインデックスでランダムにアクセスできます。Prometheusでの書き込みは追記のみであるため、異なるアクセスパターンはサンプルデータの読み取りのみに影響します。実際の影響は、元のPromQLクエリの種類に大きく依存します。

かなり無害なケースは、時間間隔内のすべてのサンプルを取得することです。これは、範囲セレクターを評価したり、スクレイプ頻度と同様の解像度でダッシュボードをレンダリングしたりする場合に発生します。Prometheus ストレージエンジンは、間隔の開始点を検索する必要があります。ダブルデルタチャンクを使用すると、バイナリ検索を実行できますが、varbit チャンクでは順番にスキャンする必要があります。ただし、開始点が検出されると、間隔内の残りのサンプルはすべて順番にデコードする必要があり、varbit エンコーディングではわずかに高価なだけです。

チャンクから少数の隣接しないサンプルを取得する場合、またはいわゆるインスタントクエリで単一のサンプルを取得する場合、トレードオフは異なります。ストレージエンジンは、返される少数のサンプルを見つけるために、多くのサンプルを反復処理する必要がある可能性があります。幸いにも、インスタントクエリの最も一般的なソースは、関連する各時系列の最新のサンプルを参照するルール評価です。完全に偶然ではありませんが、最近、時系列の最新のサンプルの取得を改善しました。基本的に、時系列に追加された最後のサンプルは現在キャッシュされています。時系列の最新のサンプルのみを必要とするクエリは、チャンク層にヒットせず、その場合、チャンクエンコーディングは関係ありません。

インスタントクエリが過去のサンプルを参照し、チャンク層にヒットする必要がある場合でも、インデックスルックアップなど、クエリの他の部分が総クエリ時間に大きく影響する可能性が高くなります。しかし、varbit チャンクに必要なシーケンシャルアクセスパターンが非常に重要になるような現実世界のクエリもあります。

varbit チャンクにとって最悪のケースのクエリとは?

varbit チャンクにとって最悪のケースは、非常に長い時系列のチャンクの中間にある1つのサンプルのみが必要な場合です。残念ながら、そのためには現実的なユースケースがあります。時系列が十分に圧縮されて、各チャンクが約8時間続くものと仮定しましょう。これは1日に約3つのチャンク、または1か月に約100のチャンクに相当します。問題の時系列を過去1か月間、100個のデータポイントの解像度で表示するダッシュボードがある場合、ダッシュボードは100個の異なるチャンクから1つのサンプルを取得するクエリを実行します。その場合でも、チャンクエンコーディングの違いは、クエリの処理時間の他の部分に比べて小さくなります。状況によっては、ダブルデルタエンコーディングでクエリが50msかかり、varbit エンコーディングで100msかかる可能性があると推測します。

ただし、ダッシュボードクエリが単一の時系列に触れるだけでなく、数千の時系列にわたって集計する場合、アクセスするチャンクの数はそれに応じて増加し、シーケンシャルスキャンのオーバーヘッドが支配的になります。(そのようなクエリは好ましくなく、通常はレコーディングルールを使用して、ダッシュボードなどで頻繁に使用されるそのようなクエリを高速化することをお勧めします。)しかし、ダブルデルタエンコーディングを使用すると、クエリ時間は許容範囲内である可能性があります(たとえば、約1秒)。varbit エンコーディングに切り替えた後、同じクエリは数十秒かかる可能性があり、これは明らかにダッシュボードでは望ましくありません。

経験則とは?

できるだけ簡単に言うと、ディスク容量とディスク操作の両方に制限がない場合は、心配せずに従来のダブルデルタエンコーディングのデフォルトを使用してください。

ただし、より長い保持時間が必要な場合、または現在ディスク操作がボトルネックになっている場合は、新しいvarbit エンコーディングを試してみることをお勧めします。Prometheus サーバーを-storage.local.chunk-encoding-version=2で起動し、varbit エンコーディングで十分な新しいチャンクが作成されるまで待ち、その効果を検証します。クエリが許容できないほど遅くなっている場合は、レコーディングルールを使用して高速化できるかどうかを確認してください。古いダブルデルタエンコーディングでも、それらのクエリは大幅に高速化される可能性が高いです。

varbit エンコーディングの内部動作に興味がある場合は、近日中に別のブログ記事をご覧ください。