mcpField
V
victoriametrics-cardinality-analysis

victoriametrics-cardinality-analysis

github.com/victoriametricsクラウド・DevOps59305 回インストール2 週間前に更新
リポジトリ

victoriametrics-cardinality-analysis について

このスキルは、TSDB の状態、メトリクスの利用統計、ラベル値のパターンを使って VictoriaMetrics の時系列カーディナリティを分析します。未使用メトリクス、高カーディナリティラベル、ヒストグラムの負荷、系列の変動を特定し、再ラベル付けやストリーム集約の設定案を示します。

主な機能

  1. 01TSDB のカーディナリティ統計を収集
  2. 02未使用・低頻度クエリのメトリクスを特定
  3. 03高カーディナリティラベルと値の傾向を確認
  4. 04ヒストグラム負荷と系列変動を分析
  5. 05再ラベル付けとストリーム集約を提案

活用シーン

  1. 01保存時系列数の増加を調査
  2. 02削除候補となる未使用メトリクスを特定
  3. 03リクエスト ID や SQL を含むラベルを検出
  4. 04メトリクスの再ラベル付けと集約を計画

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/victoriametrics/skills --skill victoriametrics-cardinality-analysis

インストール後、Claude Code で/victoriametrics-cardinality-analysisを入力して読み込まれたか確認します。

詳細

VictoriaMetrics のカーディナリティ分析

VictoriaMetrics のカーディナリティを体系的に分析します。TSDB のステータス、メトリクスの使用状況統計、ラベル値のパターンを収集し、ユーザーがそのまま適用できる具体的な relabeling とストリーム集約の設定を含む、構造化されたレポートを作成します。

目標は、最も効果の大きい最適化の機会を見つけることです。誰もクエリしていないメトリクス、監視上の価値がないのにカーディナリティを急増させるラベル、データ衛生上の問題を示すパターン(ラベルとしてのエラーメッセージ、SQL テキスト、UUID など)を特定します。

環境

victoriametrics-query スキルと同じ環境変数を使用します。

# $VM_METRICS_URL - base URL
#   cluster: export VM_METRICS_URL="https://vmselect.example.com/select/0/prometheus"
#   single: export VM_METRICS_URL="http://localhost:8428"
# $VM_CURL_CONFIG - curl config file with auth header (unset if no auth is required)
#   Remote: export VM_CURL_CONFIG="$HOME/.config/victoriametrics/curl.conf"
#   Local:  leave unset (defaults to /dev/null - no auth)

ワークフロー

フェーズ 1:データ収集

データを並行して収集するため、1 回の応答でサブエージェントを 3 つ起動します。各サブエージェントへのプロンプトには、上記の curl 認証パターンと環境変数の参照を含める必要があります。

ユーザーがスコープ(job、namespace、メトリクスのプレフィックス)を指定した場合は、TSDB ステータスクエリの match[] パラメーターと、ラベルクエリのシリーズセレクターに渡します。


サブエージェント 1:TSDB の概要

エージェント名:cardinality-tsdb | 説明:"TSDB のカーディナリティ統計を収集"

クエリ 1 — 昨日のシリーズ(最近入れ替わったシリーズを把握):

curl -q --config "${VM_CURL_CONFIG:-/dev/null}" -s \
  "$VM_METRICS_URL/api/v1/status/tsdb?topN=50&date=$(date -d 'yesterday' +%Y-%m-%d)" | jq '.data'

昨日の統計をクエリします。TSDB 全体をスキャンすることなく、今日のデータより広い範囲(すでに入れ替わっている可能性のあるシリーズを含む)を確認できます。

クエリ 2 — 今日のアクティブなシリーズ:

curl -q --config "${VM_CURL_CONFIG:-/dev/null}" -s \
  "$VM_METRICS_URL/api/v1/status/tsdb?topN=50" | jq '.data'

クエリ 3 — 既知の高カーディナリティラベルに注目:

for label in pod instance container path url user_id request_id session_id trace_id le name; do
  echo "=== focusLabel=$label ===" && \
  curl -q --config "${VM_CURL_CONFIG:-/dev/null}" -s \
    "$VM_METRICS_URL/api/v1/status/tsdb?topN=20&focusLabel=$label" | \
    jq --arg l "$label" '{label: $l, focus: .data.seriesCountByFocusLabelValue}'
done

返却内容:構造を保持したすべての生の JSON。各クエリの totalSeries、totalLabelValuePairs、seriesCountByMetricName、seriesCountByLabelName、seriesCountByLabelValuePair を含めます。


サブエージェント 2:メトリクスの使用状況統計

エージェント名:cardinality-usage | 説明:"未使用およびクエリ頻度の低いメトリクスを特定"

クエリ 1 — 一度もクエリされていないメトリクス:

curl -q --config "${VM_CURL_CONFIG:-/dev/null}" -s \
  "$VM_METRICS_URL/api/v1/status/metric_names_stats?le=0&limit=500" | jq '.'

クエリ 2 — クエリ頻度の低いメトリクス(クエリ合計数が 5 以下):

curl -q --config "${VM_CURL_CONFIG:-/dev/null}" -s \
  "$VM_METRICS_URL/api/v1/status/metric_names_stats?le=5&limit=500" | jq '.'

クエリ 3 — 統計の概要(追跡期間):

curl -q --config "${VM_CURL_CONFIG:-/dev/null}" -s \
  "$VM_METRICS_URL/api/v1/status/metric_names_stats?limit=1" | \
  jq '{statsCollectedSince: .statsCollectedSince, statsCollectedRecordsTotal: .statsCollectedRecordsTotal}'

エンドポイントがエラーを返す場合は、vmstorage で storage.trackMetricNamesStats が有効になっていない可能性があります。その旨を返却内容に記載して処理を続けてください。TSDB ステータスデータだけでも分析は可能です。

クエリ 4 — クロスチェック:「未使用」メトリクスはアラートルールで参照されているか?

curl -q --config "${VM_CURL_CONFIG:-/dev/null}" -s \
  "$VM_METRICS_URL/api/v1/rules" | jq '[.data.groups[].rules[].query]'

ルールのクエリからメトリクス名を抽出します。「未使用」メトリクスがアラートルールまたは記録ルールに含まれている場合、安全に削除できません。間接的にクエリされています。

返却内容:アラートルールとの相互参照を含む未使用メトリクス。各メトリクスを次のように分類します。

  • 削除しても安全:一度もクエリされておらず、どのルールにも含まれていない
  • ルールからのみ使用:ダッシュボードからは一度もクエリされていないが、ルールで参照されている — 意図を確認する
  • 使用頻度が低い:クエリ数が少なく、アクセス頻度が低い可能性がある(例:月次レポート)

サブエージェント 3:ラベルパターンの調査

エージェント名:cardinality-labels | 説明:「問題のあるパターンがないかラベル値を調査します」

すべてのデータは TSDB ステータスエンドポイントから取得します。/api/v1/labels や /api/v1/label/.../values は使用しないでください。

クエリ 1 — ラベルのカーディナリティ概要(ユニーク値数+シリーズ数):

curl -q --config "${VM_CURL_CONFIG:-/dev/null}" -s \
  "$VM_METRICS_URL/api/v1/status/tsdb?topN=50" | \
  jq '{labelValueCountByLabelName: .data.labelValueCountByLabelName, seriesCountByLabelName: .data.seriesCountByLabelName}'

labelValueCountByLabelName は、ユニーク値数の多い順にラベルを返します(ラベルごとの /values カウントに代わるものです)。 seriesCountByLabelName は、各ラベルが含まれるシリーズ数を示します。

クエリ 2 — focusLabel を使ったカーディナリティの高いラベルのサンプル値: クエリ 1 でユニーク値が 100 を超える各ラベルについて、サンプル値を取得します。

for label in <top labels from Query 1>; do
  echo "=== focusLabel=$label ===" && \
  curl -q --config "${VM_CURL_CONFIG:-/dev/null}" -s \
    "$VM_METRICS_URL/api/v1/status/tsdb?topN=20&focusLabel=$label" | \
    jq --arg l "$label" '{label: $l, topValues: .data.seriesCountByFocusLabelValue}'
done

seriesCountByFocusLabelValue は、シリーズ数の多い順にラベル値を返します。値の名前を使って、問題のあるパターンを検出します。

クエリ 3 — カーディナリティの高いラベルと値の組み合わせ:

curl -q --config "${VM_CURL_CONFIG:-/dev/null}" -s \
  "$VM_METRICS_URL/api/v1/status/tsdb?topN=50" | \
  jq '.data.seriesCountByLabelValuePair'

どの label=value の組み合わせが特に多くのシリーズを生み出しているかを示します。

パターン検出 — focusLabel のサンプルからラベル値を分類します。

パターン正規表現のヒント示す内容
UUID[0-9a-f]{8}-[0-9a-f]{4}-リクエスト/セッション/トレース ID がラベルとして使われています
IP アドレス\d+\.\d+\.\d+\.\d+クライアントまたはポッドごとの IP を追跡しています
長い文字列(50 文字超)長さを確認エラーメッセージ、SQL、スタックトレース
SQL キーワードSELECT|INSERT|UPDATE|DELETE|FROM|WHEREクエリテキストがラベルとして保存されています
ID を含む URL パス/api/.*/[0-9a-f]+サニタイズされていない HTTP パス
タイムスタンプエポックまたは ISO8601時刻の値がラベルとして使われています(上限なし)
スタックトレースat .*\.(java|go|py):エラーの詳細がラベルとして使われています

返却内容:ユニーク値数の多い順に並べたラベルの表。検出したパターン、focusLabel のサンプル値、シリーズへの影響を含めます。


フェーズ 2:分析

すべてのサブエージェントから結果が返されたら、調査結果をまとめて分類します。ここが分析の中核です。機械的なフィルタリングではなく、判断を適用してください。

カテゴリ 1:未使用のメトリクス(すぐに効果が出る改善)

メトリクスの使用状況統計と TSDB のシリーズ数を照合します。

  • 削除候補:queryRequestsCount=0 で、アラートルールや記録ルールで使われておらず、シリーズ数が 100 超
  • 要確認候補:queryRequestsCount=0 だがルールで参照されているもの。ルールがまだ必要か確認します
  • 優先度低:queryRequestsCount≤5 でシリーズ数が少ないもの。設定変更の手間をかける価値はありません

シリーズ数の降順に並べます。未使用のメトリクスのうち、最も規模が大きいものほど改善効果も大きくなります。

カテゴリ 2:カーディナリティの高いラベル

ユニーク値が過剰に多く、シリーズの爆発的な増加を招くラベルです。

ラベルパターン評価代表的な対処法
user_id、customer_id、account_idメトリクスラベルにしてはいけません。ログ/トレースに属する情報ですラベルを削除
request_id、session_id、trace_id、span_id相関 ID であり、メトリクスラベルにしてはいけませんラベルを削除
error、error_message、reason、status_message上限のない文字列ですラベルを削除するか、エラーコードに置き換え
sql、query、command、statementラベル内のクエリテキストに上限がありませんラベルを削除
path、url、uri、endpointサニタイズされていない場合、上限がありませんリラベルして正規化するか、ストリーム集計から除外
pod、containerk8s では一般的ですが、頻繁に変化しますポッドごとの情報が不要なら、ストリーム集計から除外
instanceノードメトリクスでは一般的ですが、アプリケーションメトリクスでは無駄ですアプリケーションレベルのメトリクスではストリーム集計から除外
le(ヒストグラムのバケット)粒度の細かいバケットは、ラベルの組み合わせごとのシリーズ数を増やしますバケット数を減らす

各調査結果について、影響を見積もります:(このラベルを持つシリーズ数)-(このラベルを持たないシリーズ数)≈ 削減できるシリーズ数。

カテゴリ 3:ヒストグラムの肥大化

_bucket で終わるメトリクスを確認します。

  • le のユニーク値はいくつありますか?
  • バケットを 1 つ追加するごとに、シリーズ数は(ラベルの組み合わせ数)倍になります
  • ほとんどのバケットが空、または重複しているヒストグラムを探します
カテゴリ 4:系列のチャーン

昨日と今日の統計を比較します:

  • 比率が 3:1 を超える場合、Pod の再起動、デプロイ、短時間で終了するジョブによる大きなチャーンが示唆されます
  • リラベルでは直接修正できませんが、dedup_interval または -search.maxStalenessInterval の調整を検討する機会を示しています

フェーズ 3:レポート

構造化されたレポートにまとめます。すべての調査結果に、影響の推定値と具体的な修正設定を含めてください。

次のテンプレートを使用します:

## VictoriaMetrics Cardinality Report — <date>

### Overview
| Metric | Value |
|--------|-------|
| Total active series (today) | X |
| Total series (yesterday) | X |
| Churn ratio (yesterday / today) | X:1 |
| Unique metric names | X |
| Stats tracking since | <date> |

### 1. Unused Metrics
**Potential savings: ~X series (Y% of total)**

| Metric | Series | Last Queried | In Alert Rules | Action |
|--------|--------|-------------|----------------|--------|
| ... | ... | never | no | Drop |
| ... | ... | never | yes — verify | Check rule |

<details>
<summary>Relabeling config to drop unused metrics</summary>

​```yaml
# Add to vmagent metric_relabel_configs (VMServiceScrape or global)
metric_relabel_configs:
  - source_labels: [__name__]
    regex: "metric1|metric2|metric3"
    action: drop
​```
</details>

### 2. High-Cardinality Labels
**Potential savings: ~X series (Y%)**

| Label | Unique Values | Top Affected Metrics | Pattern | Action |
|-------|--------------|---------------------|---------|--------|
| user_id | 50,000 | http_requests_total | UUID | Drop |
| path | 10,000 | http_request_duration | URL paths | Aggregate |
| error_message | 5,000 | app_errors_total | Long strings | Drop |

<details>
<summary>Drop labels that should never be in metrics</summary>

​```yaml
metric_relabel_configs:
  - regex: "user_id|request_id|session_id|trace_id|error_message|sql_query"
    action: labeldrop
​```
</details>

<details>
<summary>Stream aggregation for high-cardinality HTTP labels</summary>

​```yaml
# vmagent stream aggregation config
- match: '{__name__=~"http_request.*"}'
  interval: 1m
  without: [path, instance, pod]
  outputs: [total]
  # drop_input: true  # enable after verifying aggregated output

- match: '{__name__=~"http_request_duration.*_bucket"}'
  interval: 1m
  without: [pod, instance]
  outputs: [total]
  keep_metric_names: true
​```
</details>

<details>
<summary>Normalize URL paths via relabeling</summary>

​```yaml
metric_relabel_configs:
  - source_labels: [path]
    regex: "/api/v1/users/[^/]+"
    target_label: path
    replacement: "/api/v1/users/:id"
  - source_labels: [path]
    regex: "/api/v1/orders/[^/]+"
    target_label: path
    replacement: "/api/v1/orders/:id"
​```
</details>

### 3. Histogram Optimization
**Potential savings: ~X series (Y%)**

| Metric | Bucket Count | Recommendation |
|--------|-------------|----------------|
| ... | 30 | Reduce to standard 11 buckets |

### 4. Series Churn
| Observation | Value |
|------------|-------|
| Yesterday / today ratio | X:1 |
| Primary driver | Pod restarts / short-lived jobs |

### Summary
| Category | Est. Series Saved | % of Total | Effort |
|----------|------------------|-----------|--------|
| Drop unused metrics | X | Y% | Low — relabeling only |
| Drop bad labels | X | Y% | Low — labeldrop |
| Stream aggregation | X | Y% | Medium — new config |
| Histogram reduction | X | Y% | Low — bucket filtering |
| **Total** | **X** | **Y%** | |

### Implementation Priority
1. **[Low effort]** Drop unused metrics — pure relabeling, no data loss risk
2. **[Low effort]** Drop labels that should never be in metrics (IDs, messages, SQL)
3. **[Medium effort]** Stream aggregation for high-cardinality HTTP/app metrics
4. **[Medium effort]** Histogram bucket reduction

実際の調査結果に合わせてテンプレートを調整してください。該当する調査結果がないセクションは省略し、重要な調査結果があるセクションは詳しく説明してください。


修正方法のリファレンス

リラベル(metric_relabel_configs)

スクレイプ時またはリモート書き込み時に適用されます。変更は新しいデータにすぐ反映されます。

メトリクス全体を破棄する:

metric_relabel_configs:
  - source_labels: [__name__]
    regex: "metric_to_drop|another_metric"
    action: drop

ラベルを破棄する:

metric_relabel_configs:
  - regex: "label_to_drop|another_label"
    action: labeldrop

ラベル値を正規化する(一意な値を減らす):

metric_relabel_configs:
  - source_labels: [path]
    regex: "/api/v1/users/[^/]+"
    target_label: path
    replacement: "/api/v1/users/:id"
ストリーム集約

vmagent レベルで適用されます。ストレージへの書き込み前に、処理中のデータを集約します。 ドキュメント:https://docs.victoriametrics.com/victoriametrics/stream-aggregation/

メトリクスのセマンティクスを維持しながらラベルを削除する:

- match: '{__name__=~"http_.*"}'
  interval: 1m
  without: [instance, pod]
  outputs: [total]

カウンターを集約する(カーディナリティの高いディメンションを削除する):

- match: 'http_requests_total'
  interval: 30s
  without: [path, user_id]
  outputs: [total]

ヒストグラムを集約する:

- match: '{__name__=~".*_bucket"}'
  interval: 1m
  without: [pod, instance]
  outputs: [quantiles(0.5, 0.9, 0.99)]
  keep_metric_names: true

よく使われる出力関数:

関数用途例
totalカウンター(累積合計)リクエスト数
sum_samplesゲージの合計Pod 全体のメモリ使用量
count_samplesサンプル数報告を行っているインスタンス数
last最新のゲージ値現在の温度
min, max極値レイテンシのピーク
avg平均値CPU 使用率の平均
quantiles(0.5, 0.9, 0.99)分布の推定レイテンシのパーセンタイル
histogram_bucketヒストグラムの再バケット化バケットの粒度を下げる

重要:カウンターには total を、ゲージには last/avg/sum_samples を使用してください。ゲージに total を使うと、意味のない累積合計が生成されます。

Kubernetes での適用方法
方法CRD/設定スコープ
metric_relabel_configsVMServiceScrape/VMPodScrape .spec.metricRelabelConfigsスクレイプ対象ごと
グローバルリラベルVMAgent -remoteWrite.relabelConfigすべてのメトリクス
ストリーム集約VMAgent -remoteWrite.streamAggr.configリモート書き込みされるすべてのメトリクス
リモート書き込み先ごとの SAVMAgent .spec.remoteWrite[].streamAggrConfig宛先ごと

よくある間違い

間違い修正方法
アラートで使用されているメトリクスを破棄する破棄する前に、必ず /api/v1/rules と照合してください
テストせずに drop_input: true を設定するまず集約結果が想定どおりであることを確認してください
ゲージを total でストリーム集約するゲージには last、avg、または sum_samples を使用してください
keep_metric_names: true を忘れる指定しないと、出力に長い自動生成サフィックスが付きます
ヒストグラムから le ラベルを完全に削除する特定の le 値だけを削除し、ラベル自体は削除しないでください
レコーディングルールの依存関係を考慮しないアラートルールとレコーディングルールの両方を確認してください
テストせずにリラベルを適用する-dryRun フラグを使用するか、まず単一のスクレイプ対象でテストしてください

コメント