Prometheus Recording Rulesの深淵:Grafanaを高速化し、オブザーバビリティの限界を突破する設計術
Prometheusをただの「メトリクス収集ツール」として使っているなら、あなたはまだエンジンの回転数を半分も使いこなせていない。
ダッシュボードを開くたびにPrometheusのCPUが跳ね上がり、TSDBのインデックスをなめるような重いクエリを投げている現場を何度も見てきた。それは「監視」ではなく「負荷生成」だ。真のアーキテクトは、「クエリを計算するな、計算結果を読みに行け」という鉄則を知っている。
今回は、Recording Rulesを単なる「集計の自動化」から「アーキテクチャの武器」へと昇華させる極限の知見を伝授する。
—
1. Recording Rulesの真髄:動的クエリからの脱却
Prometheusにおける `Instant Query` や `Range Query` は、リクエストのたびにTSDBを走査し、フィルタリングし、関数を適用する。数千のインスタンス、数万の時系列データが混在する環境で、これをブラウザから叩けば、ユーザーは待ちぼうけを食らい、サーバーは計算資源を浪費する。
Recording Rulesの核心は「計算の非同期化」にある。 評価間隔(通常は `evaluation_interval`)ごとにあらかじめ計算結果を新しい時系列として保存しておくことで、Grafana側は「計算済みの値」をただ取得するだけになる。これにより、描画速度は文字通り10倍、いや、複雑な集計であればそれ以上に跳ね上がる。
—
2. 実践:高負荷クエリを「事前計算」に変換する設計パターン
パターンA:高解像度から低解像度へのダウンサンプリング(SLI/SLO用)
エラー率などのSLIは、長期間のダッシュボード表示で最もコストがかかる。
groups:
- name: slis.rules
interval: 1m
rules:
# 1分間のエラー率を事前計算。これにより、グラフ表示時に重い `rate()` を走らせずに済む
- record: job:http_requests_error_rate:rate1m
expr: |
sum by (job, status_code) (rate(http_requests_total{status_code=~”5..”}[1m]))
/
sum by (job, status_code) (rate(http_requests_total[1m]))
パターンB:階層的集計(Hierarchical Aggregation)
「全リージョン > 特定サービス > インスタンス」という階層がある場合、いきなり全集計をクエリするのは愚策だ。
1. レベル1(Raw): インスタンス単位(`job, instance`)
2. レベル2(Intermediate): サービス単位(`job`)
3. レベル3(Global): リージョン・環境単位(`env`)
このように、計算結果を次のRecording Ruleの入力にすることで、計算量を指数関数的に削減できる。
—
3. 命名規則とディレクトリ構成:数万ルールを統治する
ルールが増殖すると、管理不能なスパゲッティ状態になる。私は以下のディレクトリ構成を強く推奨する。
prometheus/rules/
├── 00_base/ # インフラ基盤メトリクス(node_exporter等)
├── 10_services/ # サービスごとのドメインメトリクス
│ ├── api-gateway/
│ │ ├── latency.rules.yml
│ │ └── error.rules.yml
│ └── auth-service/
└── 99_globals/ # サービス横断的なSLO計算
命名の極意:`namespace:metric_name:op` 形式
Prometheus公式のベストプラクティスをさらに厳格化し、以下の構造を守れ。
- `namespace` : サービスの識別子
- `metric_name` : 扱っているメトリクス
- `op` : 適用した関数や集計軸(例: `sum`, `avg`, `rate1m`)
例: `gateway:request_duration_seconds:avg_rate5m`
これを見るだけで、誰が、何を、どう計算したかが一目でわかる。
—
4. アーキテクトの隠し技:メモリと計算負荷の最適化ハック
Recording Rulesを使いすぎると、今度はPrometheus自体のメモリ使用量(RAM)が限界を迎える。
1. `evaluation_interval` の個別最適化
全てのルールをデフォルトの15秒で回す必要はない。`interval: 1m` や `interval: 5m` を適切に設定し、重要度の低いメトリクスは評価頻度を下げろ。
2. 「録画の録画」によるメモリ節約
巨大な集計結果をメモリ上に保持するのを避けるため、中間結果を適宜ルールとして切り出す。
- Bad: `sum(huge_metric_a + huge_metric_b + …)`
- Good:
- `tmp:metric_a_plus_b = huge_metric_a + huge_metric_b`
- `final:result = sum(tmp:metric_a_plus_b)`
3. APIによる動的ルールの管理(自動化)
手動でYAMLを編集するのは時代遅れだ。CI/CDパイプラインから `promtool` を叩き、構成変更を検知したら `/-/reload` を投げるのは基本。さらに一歩進むなら、`thanos-ruler` を活用し、Prometheus本体の負荷をオフロードする設計を検討すべきだ。
—
最後に:オブザーバビリティの魂
Recording Rulesの設計は、あなたのシステムの「急所」を見抜く力そのものだ。どこでボトルネックが発生し、どのクエリが最もリソースを食いつぶしているか。それを把握し、あらかじめ計算して道を舗装しておくことこそが、卓越したエンジニアの仕事である。
計測可能なものは、最適化できる。
そして最適化されたシステムだけが、障害の予兆を静かに、かつ確実に捉えることができるのだ。
さあ、今すぐダッシュボードのクエリ実行ログを開き、最も重いクエリを「録画」しに行こう。現場からは以上だ。