# Materialized Metrics in Prometheus Navigation: [[Reddit]] | [[Prometheus]] | [[Prometheusシリーズチャーン]] | [[マテリアライズドメトリクス]] **著者**: [[Aleksandr Krivoshchekov]]・[[Walther Lee]]([[Reddit]] オブザーバビリティチーム) **媒体**: Reddit 公式ブログ(r/RedditEng クロスポスト) **取得方法注記**: reddit.com は Cloudflare の JS 認証チャレンジを要求し、WebFetch・curl(ブラウザ UA・公式 JSON API 含む)いずれからも本文取得不能だった。ユーザーが記事本文全文とコメント欄をチャットに直接貼り付けたものを一次資料として使用した。confidence: medium(公開日不明、貼り付け経由のため書式の欠落リスクあり)。 --- ## 概要 Prometheus の系列識別モデル(`metric_name + labels = time_series`)は、Kubernetes の `pod` ラベルのようにインフラ都合で変動するラベルに対して脆弱で、ロールアウト・スケールアウト・pod 障害のたびに系列数が膨張する。Reddit のオブザーバビリティチームは、この問題を「スクレイプ時にラベルを畳み込んで集約する」ことで解決しようとした。素朴な合算はカウンタの累積性(cumulative)によって破綻するため、値を delta(差分)化してから合算する必要がある。しかし delta はクエリの時間窓に依存し、かつレプリカ間で状態を共有できない。この記事は、delta をスクレイプ間隔ごとにリセットする「**ジグザグカウンタ(zigzag counter)**」という単純な仕掛けで、レプリカ間の合意なしに比較・重複排除・欠損補完が可能な擬似カウンタを作り、本番で系列数88%削減・レイテンシ80%削減・忠実度99.85%を達成した過程を述べる。 ## 問題: pod ラベルによる系列爆発 - カウンタ系列はレプリカ(pod)ごとに別ラベルセットとして記録する必要がある。さもないと「pod-a が5カウント、pod-b が3カウント」を区別できず合算すら不能になる。 - pod はデプロイ・オートスケール・障害・単純な再スケジューリングで頻繁に入れ替わり、その都度新しい系列が生まれる。ロールアウト1回で系列数が倍増し、ロールバックでさらに倍増しうる。 - Reddit の各サービスは常時数十億の系列を露出しており、大規模デプロイでは1メトリクス名だけで数百万カウンタになりうる。 - プロダクトチームは pod 単位の分離を望んでおらず、デプロイ全体の合計リクエスト数・エラー数・レイテンシしか見たくない。インフラ実装の詳細が可観測性に漏れ出している状態。 ![[_attachments/materialized-metrics-in-prometheus/fig01-pod-churn-series-explosion.png]] (定常状態では pod は固定的だが、実運用ではデプロイ・スケールアップ・pod 障害によって pod 名が入れ替わり続け、同一メトリクスに対するユニーク系列数が線形に積み上がっていく様子を示す図。Source: Materialized Metrics in Prometheus) ![[_attachments/materialized-metrics-in-prometheus/fig02-desired-aggregated-view.png]] (ユーザーが実際に見たいのは pod 単位の内訳ではなく、こうした集約済みのダッシュボード全体像であるという例。Source: Materialized Metrics in Prometheus) ## 検討した既存の解法とその限界 - **クエリ時集約**(`sum without (pod)(rate(...))`): これが素の現状追認であり、系列数の急増がそのままクエリレイテンシの急増に直結する。デプロイのたびにクエリが遅くなることをユーザーは想定していない。 - **recording rule でラベルを削除**: 大規模では rule 評価自体がクエリ評価とほぼ同等のコストを要し、レイテンシ問題を「クエリ時」から「継続的なバックグラウンド負荷」へ移すだけ。事前にルールを定義する toil が発生し、インシデント時に必要なクエリを予測できない。系列数が急増すればルール自体もタイムアウトしうる。 ## スクレイプ時集約への転換とカウンタの累積性問題 - recording rule の逐次評価に対し、Prometheus のスクレイプは並行実行されるため、スクレイプ時に集約すれば計算資源をより効率的に使える。 - しかし Prometheus のカウンタは累積型(増加のみ、または 0 へのリセット)であり、生値をそのまま合算すると reset を跨いだ際に増分が過大評価される。`increase()` が期待する正しい delta 系列 `+21 +15 +12 +15`(合計63)に対し、素朴な合算では `+21 +15 +34 +15`(合計85)になるという具体例で破綻を示している。 ![[_attachments/materialized-metrics-in-prometheus/fig03-sum-rate-vs-rate-sum.png]] (reset がなければ `sum(rate)` と `rate(sum)` はほぼ一致するが(左)、reset を数回挟むだけで `rate(sum)` が `rate` の補正機構と衝突し不釣り合いに高い値を返す(右)ことを示す比較図。Source: Materialized Metrics in Prometheus) - 解決策は、値を累積のまま合算するのではなく **delta(差分)** に変換してから合算すること。delta は前回値の記憶を持たないため、pod の再起動によるギャップは単なる欠損として残るだけで、合算に特別な補正処理が不要になる。 ![[_attachments/materialized-metrics-in-prometheus/fig04-cumulative-counter-vs-delta.png]] (pod 再起動時、累積カウンタ(左)は値が一度落ち込んでから再度立ち上がるのに対し、delta(右)は単にギャップが空くだけで前の値を引きずらない。この性質が delta を合算に適した表現にする。Source: Materialized Metrics in Prometheus) ## The ZigZag: delta を擬似カウンタへ戻す - delta 化には固定の時間窓が要るが、チームのクエリ窓は数分〜数時間と多様であり、単一の delta 間隔に固定するか、delta を累積カウンタへ戻す方法が必要になる。 - OpenTelemetry・VictoriaMetrics には delta⇔累積変換プロセッサが既にあるが、累積カウンタは状態を持つため単一コレクタ内でしか正しく計算できない。開始時刻の異なる複数レプリカに負荷分散すると、レプリカ間の累積合計が一致せず、互いの欠損を埋め合えない。 - 他の手法(ストリーミング外部コンポーネント・確率的アルゴリズム・プロキシ・remote-write・プロセッサ)は誤差率9%程度が相場だったが、Reddit チームはより単純な発想を試した: **累積カウンタが「累積」でいられる最短スパンはスクレイプ間隔そのものである**。 - delta をスクレイプ間隔ごとに強制リセットすると、増加はするが定期的にゼロ付近へ戻る「ジグザグ」状のカウンタになる。アルゴリズムは次の擬似コードで表される。 ``` last = 0 for every 15s: delta = delta_since_last_flush() if delta < last: last = delta else: last = delta + last flush(last) ``` ![[_attachments/materialized-metrics-in-prometheus/fig05-zigzag-counter-from-delta.png]] (下段の delta 系列から上段のジグザグ累積カウンタが生成される様子。ジグザグは一定周期で増加とリセットを繰り返す鋸波状になる。Source: Materialized Metrics in Prometheus) ## レプリカ間重複排除とジグザグ制約 - ジグザグカウンタはレプリカごとに周波数は異なるが値のスケールが揃うため、一方で他方の欠損を埋めたり重複排除したりできる。サンプル5点で平均誤差率0.15%という高精度を達成した。 - 数ヶ月間のテスト運用(約400万系列)で、系列数の多いメトリクス名についてクエリ負荷・スループットを旧来比3%まで削減。追加のメモリオーバーヘッドはほぼ観測されなかった。 - **課題**: Prometheus は2時間ブロック単位でデータを保存するため、複数ブロックにまたがる長時間クエリでは異なるレプリカのジグザグ間を移動する際に重複排除が破綻するケースが見つかった。ほぼ同時刻でわずかに値が下がった連続サンプル(例: `25.49@…598` → `25.42@…607`)が「リセット」と誤認され、9秒で約25という異常なレートを生む。 - 対策として、ジグザグカウンタの生成関数に「連続する減少を1回までしか許さない」制約を追加し、真のジグザグパターンを強制。これにより、パターンを破る値(=レプリカ切り替わりの証拠)を明示的に除外できるようになった。 - レプリカ切り替わり時に生じる二重の谷を解消する際、単純に「直近の谷」を除去するのではなく **先読みして最初の谷を除去する** ことで、両方のストリームで滑らかな移行が得られることを具体例で示した(`22 50 21 50` / `48 19 52 20` → 先読み除去でシームレスな delta 系列 `28 21 29 19 34 20` を得る)。 ## 本番結果 - Prometheus フォークに実装し本番の一部インスタンスへ展開。 - 最大のメトリクスでは系列数を旧来比2%まで削減、全クエリ平均でスループット12%・レイテンシ20%まで削減(=スループット88%減・レイテンシ80%減に相当)。 - メモリオーバーヘッドは新規ジグザグ系列分以外にほぼなし。CPU使用量は6%増加したが、既存 recording rule の置き換えで相殺可能。 - 生データとの平均誤差率0.15%(標準偏差0.13%)。 - 計測対象: 毎秒100万サンプル超・70Gi メモリ・16コアのインスタンス。集約前1700万系列、集約後に新規ジグザグ系列200万を追加。 ![[_attachments/materialized-metrics-in-prometheus/fig06-counter-vs-zigzag-vs-rate.png]] (左上: アプリケーションが露出する標準的な累積カウンタ。右上: 同じカウンタのジグザグ表現。下段: 両者から算出した秒間カウント数はほぼ一致する。Source: Materialized Metrics in Prometheus) ## 限界とトレードオフ - 本手法はカウンタおよびカウンタ相当型(Prometheus classic histogram 等)にのみ適用可能。gauge・summary・native histogram には別の集約が必要。 - Prometheus の既存のカウンタリセット認識の限界(スクレイプ間で pod が再起動し、新プロセスが前回値より高い値に達した場合、reset を検知できず delta を過小評価する)は本手法でも解消されない。 - **replica-local な可視性の限界**: 集約は各 Prometheus レプリカが自身のスクレイプ結果のみを用いて独立に実行する。一方のレプリカだけがターゲットへの接続を失うと、他方で集約できていたサンプルが欠落し、両者を比較・補完できない。これは recording rule が元々持つ制約と同じであり、Reddit チームは「軽量な暗黙の recording rule」と位置づけている。 - 実装では生メトリクスを削除せず温存し、集約系列はあくまで最適化パスとして追加している。デバッグや pod 単位クエリのために生データが必要なため。将来的には集約後に生データを削除してメモリを削減する余地があるが、これは recording rule では持ち得なかった選択肢だとしている。 ## 次のステップ チームはこの機能を独自フォークから OSS 版 Prometheus へアップストリームし、コミュニティでの議論・検証・改善を経て公開する意向を示している。 ## コメント欄の議論 - **Watchful1**(2026-07-20、3 points): 自社は VictoriaMetrics へ移行することでこの問題を解決したと指摘。エンドユーザー視点では Prometheus と区別がつかず、streaming aggregation によるラベル削除(ingest 時)をより単純にサポートし、CPU・ストレージ両面で高性能だとコメント。 - **jcol26**(2026-07-25、1 point): 通常の Prometheus か、Cortex・Mimir・Thanos のいずれかを使っているのか(数十億系列規模ならそのいずれかのはずだ、という推測付き)と質問。記事側はどちらにも明示的に回答していない。 ## 限界・不確実点 - 記事の公開日が本文・コメント欄いずれからも明示されておらず、最古のコメント日付(2026-07-20)から遡って推定するしかない。 - reddit.com への直接アクセスが Cloudflare の JS 認証チャレンジで一貫してブロックされたため、本文はユーザー貼り付けのテキストに依拠しており、原文の書式(強調・リンク)の一部が失われている可能性がある。 - ジグザグカウンタの本番実装(Prometheus フォークの具体的なコード)は公開されておらず、アップストリーム化の進捗も本記事からは分からない。 - VictoriaMetrics 等の streaming aggregation との定量比較(コメント欄で言及されるのみ)は本記事に含まれていない。 ## 概念・実体への接続 - [[Aleksandr Krivoshchekov]] / [[Walther Lee]](著者) - [[Reddit]](所属組織) - [[Prometheus]](対象システム) - [[Prometheus TSDB]](カウンタ累積セマンティクスの背景) - [[Prometheusシリーズチャーン]](本記事が扱う根本問題と同一系統) - [[マテリアライズドメトリクス]](本記事が提案する中心手法)