PromQLの深淵へ:Dashboardが「重い」という悲劇を終わらせる5つの極意
「Grafanaのダッシュボードを開くたびにコーヒーを淹れに行く」。そんな運用は今すぐ終わらせるべきだ。
Prometheusは強力だが、その力は「書き方」一つで毒にも薬にもなる。多くのエンジニアが陥る罠は、Prometheusをリレーショナルデータベースのように扱おうとすることだ。PromQLは時系列データの演算エンジンであり、クエリの書き方が計算コスト(CPU/メモリ)に直結する。
今日は、現場で血を流しながら学んだ「PromQLの最適化」と、プロの現場で必須となる周辺環境のベストプラクティスを伝授する。
—
1. 【計算の掟】Subqueryは「最後の手段」と心得よ
`[5m:10s]` のようなサブクエリは便利だが、その裏で何が起きているか想像したことはあるか? 指定範囲内を細かいステップで全走査し、メモリ上に一時的な時系列データを生成する。
- アンチパターン: 頻繁に更新するパネルで無意味にサブクエリを使う。
- 最適解: 可能であれば、記録ルール(Recording Rules)を使い、計算結果を事前にプリセットせよ。
- `rate(http_requests_total[5m])[30m:1m]` を書く前に、その計算結果を `rule_group` で保持し、そのメトリクスを参照するだけで済むように設計する。
2. `rate` vs `increase`:数学的性質を見極めろ
よくある誤解だが、`increase` は内部的に `rate` に変換される。重要なのは「単位」だ。
- 絶対ルール:
- 秒間平均を見たいなら `rate()` を使え。
- 指定期間の合計値を見たいなら `increase()` を使え。
- パフォーマンスの要諦: どちらを使う場合も、`[range]` の期間は「スクレイプ間隔の少なくとも4倍以上」に設定せよ。範囲が狭すぎると、Prometheusが補間計算に失敗し、グラフが歯抜けになる。逆に広すぎると、計算コストが爆発する。
3. ラベルセレクタは「左寄せ」で絞り込め
PromQLのパフォーマンスは、最初にどれだけ時系列の母集団を削れるかにかかっている。
- 悪い例: `sum(rate(http_requests_total[5m])) by (status)`
- 全メトリクスをメモリにロードしてから集計している。
- 良い例: `sum(rate(http_requests_total{job=”api-server”}[5m])) by (status)`
- 必ず `job` や `instance` などの高カーディナリティなラベルを先頭で指定し、スキャン範囲を最小化する。
4. `sum by` の順序でCPU負荷を減らせ
集計関数(sum, avg, max)は、必ず「集計してからラベルを捨てる」のが鉄則だ。
- 悪手: `sum(rate(my_metric[5m]))`
- 一手: `sum by (label_name) (rate(my_metric[5m]))`
- `by` を指定しない場合、Prometheusは全ラベルを保持しようと必死になる。不要なラベルは即座に切り捨ててメモリを解放せよ。
5. カーディナリティ爆発を物理で殴れ
クエリが遅い原因が「Prometheusのストレージにある」場合、クエリをいくら磨いても無駄だ。
- 神設定: `count({__name__=~”.+”})` で、今いくつの時系列を保持しているか確認せよ。もしこれが数百万を超えているなら、ラベルに「ユニークなID(ユーザーIDやセッションID)」を突っ込んでいないかチェックしろ。それはPrometheusの死を意味する。
—
現場を支える「プロのツールボックス」
Grafana 必須プラグイン
- [Prometheus Data Source](https://grafana.com/grafana/plugins/prometheus/): 基本だが、”Exemplars”を有効にしろ。トレースIDとメトリクスがグラフ上でリンクする世界は、一度味わうと戻れない。
- [Infinity](https://grafana.com/grafana/plugins/grafana-infinity-datasource/): 外部APIのJSONもPrometheusのグラフと重ね合わせろ。CI/CDのデプロイ時間とエラーレートを同一軸で見るのが、真のオブザーバビリティだ。
チームで共有すべき「Recording Rules」のベストプラクティス
`rules.yaml` は、ただ定義するだけでなく「名前空間」を明確にせよ。
groups:
- name: api_service_rules
interval: 1m # 頻繁に計算させる必要はない
rules:
# 生のメトリクスを触らせず、計算済みメトリクスを全員に使わせる
- record: job:http_requests:rate5m
expr: sum by (job, status) (rate(http_requests_total[5m]))
開発スピードを上げるショートカット(Grafana)
- `e`: ダッシュボードの編集モード切り替え
- `p` + `d`: ダッシュボード設定を開く
- Dashboard JSONの共有: 毎回GUIでポチポチするのは三流だ。ダッシュボードは `JSON` としてGit管理し、`grafana-reporter` や `terraform` でプロビジョニングせよ。
—
最後に:オブザーバビリティは「哲学」である
PromQLの最適化とは、単なる計算速度の向上ではない。「システムが今、何に苦しんでいるのか」を、最小のコストで正確に可視化するための「問いの磨き上げ」である。
君たちが書く一行のクエリが、障害発生時のエンジニアの救いになる。
重いグラフを放置することは、未来の仲間の工数を奪うことに他ならない。
さあ、ダッシュボードを開き、`Explain` や `Query Inspector` を使って、そのクエリの「真の姿」を覗いてみるといい。驚くような無駄が、そこに隠れているはずだ。