Prometheusの魂を殺すな:カーディナリティ爆発を制するデータモデリングの極意
Prometheusを運用していて、「突然のOOM(Out of Memory)」「クエリのタイムアウト」「スクレイピング間隔の遅延」に直面したことはないだろうか?
もし心当たりがあるなら、君のPrometheusは「カーディナリティ爆発」という癌に侵されている。本稿では、世界中の現場を渡り歩いてきたオブザーバビリティ・アーキテクトの視点から、Prometheusの性能を殺さず、かつ「本当に見たい指標」を可視化するためのデータモデリングの極意を伝授する。
—
1. カーディナリティ爆発:Prometheusの「死」へのカウントダウン
Prometheusのデータ構造において、`{label=”value”}` の組み合わせ一つひとつが「時系列(Time Series)」となる。この組み合わせ総数が「カーディナリティ」だ。
なぜこれが危険なのか?
Prometheusは、これら全ての時系列のインデックスをメモリ上に保持する。カーディナリティが爆発すると:
- メモリ枯渇: インデックスだけで物理メモリを食い潰し、カーネルがOOM Killerを呼ぶ。
- クエリの遅延: 範囲ベクトル(Range Vector)の計算時に、膨大な時系列を舐めるためCPUが焼き切れる。
- ディスクI/Oの飽和: 書き込み(TSDBのチャンク生成)が追いつかなくなり、スクレイピングに失敗する。
「とりあえず何でもラベルに入れとけば後で分析できるよね」という甘い考えは、Prometheusにおいては「運用停止への特急券」であることを理解してほしい。
—
2. 絶対にラベルに含めてはいけない「NGデータ」
以下の値は、ラベルのカーディナリティを指数関数的に増大させる典型的な「爆弾」だ。
- UUID / GUID: ユーザーID、トランザクションID、リクエストID。これらは無制限に生成される。
- タイムスタンプ: `created_at` や `request_time` をミリ秒単位でラベルにするのは言語道断。
- 高頻度なURLパラメータ: `?query=…` のような動的なクエリ文字列。
- メールアドレスや個人名: ユーザー数に比例して増大するデータは、オブザーバビリティの対象外(あるいはログ側で処理すべき)。
鉄則: 「有限かつ、集約可能な値」以外はラベルにするな。
—
3. 実践:ラベル設計とリネーミングの魔術
どうしても動的な情報が必要な場合は、`label_replace` を使って「高カーディナリティな値を切り捨てる」のがプロの技だ。
ラベルリネーミングのベストプラクティス
例えば、URLからIDを抜き出して汎用化する設定例(`prometheus.yml`)を見てほしい。
scrape_configs:
- job_name: ‘api-server’
relabel_configs:
# URLからIDのような可変部分を除去して正規化する
- source_labels: [__address__]
regex: ‘/api/users/([0-9]+)/profile’
replacement: ‘/api/users/:id/profile’
target_label: ‘endpoint’
このように、「人間が分析しやすい粒度」に事前に丸めるのが、アーキテクトとしての手腕だ。
—
4. チーム開発を劇的に加速させる「神・設定術」
開発スピードを上げるキーボードショートカット(Prometheus UI)
Web UIを直接叩く際は、これらを指に覚え込ませろ。
- `Alt + Enter`: クエリの実行(マウスに手を伸ばす時間は無駄だ)
- `Ctrl + Space`: クエリのオートコンプリート(関数やメトリクス名を暗記するな、補完を使え)
絶対入れるべき神プラグイン:`PromLens`
PromQLを書いていて「なぜこの値が出るのか?」と迷う時間は、PromLens(Julius Volz氏が開発)を導入することで解消できる。クエリの実行計画を可視化し、どのラベルがカーディナリティを押し上げているかを瞬時に特定できる。
設定ファイルの共有化ルール
設定ファイルは「DRY(Don’t Repeat Yourself)」を徹底せよ。
良い設定の構成例: 共通部分はファイル分割
prometheus.yml
rule_files:
- “rules/.rules.yml” # アラート定義を別出しにする
rules/api.rules.yml
groups:
- name: api_latency
rules:
- alert: HighLatency
expr: histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, endpoint)) > 0.5
for: 1m
labels:
severity: critical
—
アーキテクトからの最終警告
「メトリクスは、システムの健康状態を語るための最小限の言語であるべきだ」
ラベルの数は、システムの複雑さに比例して増えていく。だからこそ、監視対象を定義する段階で「このラベルで何を分析するのか?」「このラベルは数千件以上の値を取りうるか?」を自問自答せよ。
カーディナリティを制する者は、Prometheusを制す。そして、Prometheusを制する者は、システムのダウンタイムを最小化し、心穏やかなエンジニアリングライフを送ることができるのだ。
さあ、今すぐ君の `prometheus.yml` を開き、不要なラベルを削ぎ落とせ。それが、最高のパフォーマンスへの第一歩だ。