用 Prometheus metric_relabel_configs 在抓取阶段丢弃高基数标签

举报
yd_250998817 发表于 2026/11/10 12:37:29 2026/11/10
【摘要】 针对标签爆炸造成的序列数膨胀与查询变慢,给出 Prometheus metric_relabel_configs 的 labeldrop、drop、keep 配置示例,说明热加载方法和用 /api/v1/series 与查询接口做前后对比的步骤,并列出边界与限制。

用 metric_relabel_configs 在抓取阶段丢弃高基数标签

问题场景

某个业务的 /metrics 里带了请求级别的标签:trace_id、request_id、user_id,还有 url 这种把路径参数直接拼进去的标签。每个不同取值都会产生一条新序列,序列数会随流量线性膨胀。随之而来的典型现象是:Prometheus 常驻内存一路上涨,/api/v1/series 响应越来越慢,面板查询从百毫秒级掉到秒级,WAL 与数据块也明显变大。

这类标签对聚合没有贡献——sum by (path, code) 根本用不到 trace_id。比起事后在 PromQL 里用 without / ignoring 处理,更划算的做法是在样本写入 TSDB 之前就把它们丢掉。metric_relabel_configs 就是承担这件事的阶段。

两个 relabel 阶段的分工

配置里有两个同名但位置不同的 relabel 段:

  • relabel_configs:抓取之前,作用于 target 的标签(__address__、__meta_* 等),用来筛目标、改地址、拼标签。
  • metric_relabel_configs:抓取响应解析完成、写入 TSDB 之前,作用于每一条样本的标签集合(包含 __name__),用来丢指标、丢标签。

下面只讨论第二个。

最小可运行示例

global:
  scrape_interval: 15s

scrape_configs:
  - job_name: demo-app
    metrics_path: /metrics
    static_configs:
      - targets: ["10.0.0.11:8080"]   # 占位地址,替换成自己的实例
    metric_relabel_configs:
      # 1) 按标签名丢弃:注意 regex 匹配的是标签名,不是标签值
      - action: labeldrop
        regex: "trace_id|request_id|session_id|user_id"

      # 2) 按指标名丢弃整条指标
      - action: drop
        source_labels: [__name__]
        regex: "debug_.*|go_gc_.*"

      # 3) 按标签值丢弃:只保留已知的几个取值
      - action: drop
        source_labels: [status]
        regex: "unknown|other|none"

如果需要白名单模式,把第 2 步换成正则范围足够窄的 keep:

      - action: keep
        source_labels: [__name__]
        regex: "http_requests_total|process_resident_memory_bytes|up"

几个容易踩的点:

  • relabel 里的正则是整串锚定的,trace_id 只匹配名为 trace_id 的标签,不会匹配 trace_id_xxx。
  • 规则从上到下顺序执行,后面的规则看到的是前面处理后的结果。把 keep 白名单写在 drop 后面,效果会和预期不一致。
  • labeldrop 是把这个标签名从该次抓取的所有样本上摘掉,同一 job 内无法只针对某一条指标;只想处理特定指标时,用 source_labels: [__name__, trace_id] 组合条件配合 drop 更精准。
  • up、scrape_duration_seconds 这类抓取元数据由 Prometheus 自身生成,不受 metric_relabel_configs 影响。

验证:序列数与时延

热加载需要开启 lifecycle 参数:

prometheus --config.file=prometheus.yml --web.enable-lifecycle

改完配置后触发 reload:

curl -s -X POST http://127.0.0.1:9090/-/reload

统计某条指标的序列数(返回数组长度即序列条数):

curl -sG http://127.0.0.1:9090/api/v1/series \
  --data-urlencode 'match[]={__name__="http_requests_total"}' \
  | jq '.data | length'

对比查询耗时,取接口返回的统计字段而不是凭感觉:

curl -sG http://127.0.0.1:9090/api/v1/query \
  --data-urlencode 'query=sum by (path, code) (rate(http_requests_total[5m]))' \
  --data-urlencode 'stats=all' \
  | jq '.data.stats.timings'

建议在负载相近的时间点各测一次:一次在 reload 之前,一次在 reload 之后跑过若干个抓取周期再测,分别记录序列数与 evalTotalTime。需要注意热加载只是改变写入行为,历史数据里的旧序列仍然存在,要等 --storage.tsdb.retention.time 到期清理才会消失,所以序列数对比最好限定在新写入的时间窗口上,不要拿含历史数据的区间直接比较。

边界与限制

  • 抓取端仍然要拉取并解析完整响应,网络带宽与解析的 CPU 开销不会因此下降,节省的是存储、内存和查询时的序列基数。
  • metric_relabel_configs 只能依据标签名、标签值和指标名判断,无法按指标取值的大小做丢弃。
  • 丢标签等于合并序列,聚合结果的维度会变少,已有的 recording rule、告警表达式和面板需要用新的标签集重新核对。
  • histogram 的 le、summary 的 quantile 不能被删除,否则指标语义完全失真。
  • 正则每次抓取都会执行,避免写成 .* 这类过于宽泛的匹配,也别把大量无关规则堆在同一个 job 上。
  • 丢弃标签前先确认该标签没有用于路由、分片或外部对齐,例如用 instance 做多副本去重时要保留它。

总结一下:把高基数标签的处理从查询侧前移到抓取侧,配置量很小,但需要配合序列数与查询耗时的前后对比来确认效果,并对聚合语义的变化做一次完整回归。

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。