mcpField
V
victoriametrics-cardinality-analysis

victoriametrics-cardinality-analysis

github.com/victoriametrics云与 DevOps59305 次安装2 周前更新
代码仓库

关于 victoriametrics-cardinality-analysis

该技能通过查询 VictoriaMetrics 的 TSDB 状态、指标使用统计和标签值模式,分析时间序列基数问题,适用于希望优化指标存储的数据运维人员。它会整理未使用指标、高基数标签、直方图开销和序列变化,并给出重标记或流聚合配置建议。

主要功能

  1. 01收集 TSDB 基数统计
  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 状态、指标使用统计和标签值模式,然后生成结构化报告,其中包含用户可直接应用的具体重标记和流聚合配置。

目标是找出影响最大的优化机会——无人查询的指标、没有监控价值却导致基数激增的标签,以及表明数据卫生问题的模式(将错误消息、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:数据收集

在单次响应中启动 3 个子 Agent,并行收集数据。每个子 Agent 的提示词都必须包含上文中的 curl 身份验证模式和环境变量引用。

如果用户指定了范围(job、namespace、指标前缀),则将其作为 match[] 参数传递给 TSDB 状态查询,并作为序列选择器传递给标签查询。


子 Agent 1:TSDB 概览

Agent 名称: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。


子 Agent 2:指标使用统计

Agent 名称: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]'

从规则查询中提取指标名称。任何出现在告警规则或记录规则中的"未使用"指标都不适合直接删除——它们会被间接查询。

返回内容:未使用指标及其与告警规则的交叉引用。将每项标记为:

  • 可安全删除:从未查询,且未出现在任何规则中
  • 仅被规则使用:仪表板从未查询,但被规则引用——请确认是否符合预期
  • 极少使用:查询次数少,可能仅偶尔访问(例如,每月报告)

子 Agent 3:标签模式检查

Agent 名称: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+按客户端或 Pod 跟踪 IP
长字符串(>50 个字符)长度检查错误消息、SQL、堆栈跟踪
SQL 关键字SELECT|INSERT|UPDATE|DELETE|FROM|WHERE将查询文本存储为标签
含 ID 的 URL 路径/api/.*/[0-9a-f]+未清理的 HTTP 路径
时间戳epoch 或 ISO8601将时间值用作标签(无界)
堆栈跟踪at .*\.(java|go|py):将错误详情用作标签

返回内容:按唯一值数量排序的标签表,包含检测到的模式、来自 focusLabel 的样本值以及序列影响。


第 2 阶段:分析

所有子 Agent 返回结果后,汇总并分类发现。这是分析的核心——要运用判断,而不是机械地筛选。

类别 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、container对 k8s 来说很常见,但变动频繁如果不需要按 Pod 统计,则不按其流式聚合
instance对节点指标来说很常见,对应用指标来说则浪费资源对应用级指标不按其流式聚合
le(直方图桶)细粒度的桶会使每种标签组合对应的序列数倍增减少桶数量

对于每项发现,估算影响:(包含此标签的序列数)-(不包含此标签的序列数)≈ 节省的序列数。

类别 3:直方图膨胀

检查以 _bucket 结尾的指标:

  • 有多少个唯一的 le 值?
  • 每增加一个桶,序列数就会乘以(标签组合数量)
  • 查找大多数桶都为空或重复的直方图
类别 4:序列 churn

比较昨天和今天的统计数据:

  • 比例 >3:1 表明 pod 重启、部署、短时任务导致了明显的 churn
  • 无法直接通过重新标记修复,但表明可以调整 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 标志,或先在单个抓取目标上测试

评论

支持 Markdown