Prometheus 高基数治理:把 120 万 series 压到 18 万

举报
yd_216677863 发表于 2026/10/28 10:01:06 2026/10/28
【摘要】 Prometheus 内存暴涨、查询超时的常见元凶是指标基数失控。本文用一次真实的 120 万 series 治理过程,拆解基数来源定位、relabel 丢弃、histogram 分桶改造、recording rule 预聚合四步落地方法,附可直接套用的 PromQL 与配置片段。

一、现象:内存 3 天涨到 28G

一套 6 节点 Kubernetes 集群的 Prometheus 在升级业务后出现三个症状:进程 RSS 三天从 6G 涨到 28G;rate(http_request_duration_seconds_count[5m]) 查询 P99 从 300ms 恶化到 11s;TSDB 压缩任务持续超过 40 分钟,导致 prometheus_tsdb_compaction_chunk_range_seconds 报警。

排查第一步永远不是加内存,而是数 series。

prometheus_tsdb_head_series            # 当前活跃 series 数
scrape_samples_scraped                 # 每个 target 抓到的样本数

实测 head_series 达到 121 万,其中 68% 来自 3 个业务 target。

二、定位:谁在贡献基数

按 job 拆解基数,一条 PromQL 就能定位元凶:

topk(10, sum by (job) ({__name__=~".+", job=~".+"}))

更精确的写法是统计每个 job 下不同 label 组合的数量:

topk(10, count by (job) (group by (job, __name__, instance, path, status) ({__name__=~".+"})))

本次结果:java-app 贡献 41 万,gateway 贡献 27 万,batch-worker 贡献 14 万。根因分三类——URL 路径带 ID、错误信息进 label、客户端自造高基数标签。

三、治理四招

1. relabel 丢弃无用指标

先在抓取层砍掉业务方「顺手埋点」的指标,用 metric_relabel_configs 白名单式保留:

metric_relabel_configs:
  - source_labels: [__name__]
    regex: '(jvm_.*|http_request_duration_seconds.*|process_.*|node_.*)'
    action: keep
  - source_labels: [path]
    regex: '/order/[0-9]+'
    target_label: path
    replacement: '/order/:id'
    action: replace

关键在第二条:把动态路径正则归一化,这一步单独就砍掉 19 万 series。

2. 干掉「错误信息当 label」

典型反例是 error_msg="java.net.SocketTimeoutException: Read timed out after 3000ms at ..."。错误消息每行都不同,等于每条错误创建一个新 series。

正确做法是只留错误类型,把明细打到日志:

- source_labels: [error_msg]
  regex: '.*(Timeout|Refused|Reset|Denied).*'
  target_label: error_type
  replacement: '$1'
  action: replace
- regex: 'error_msg'
  action: labeldrop

3. histogram 分桶改造

默认 prometheus.DefBuckets 有 12 个桶,一个接口就产生 12 个 series;接口维度 × 实例维度 × 方法维度相乘后基数暴涨。改造原则是桶数够用即止,按 SLO 设边界:

// 原来 12 桶,改为 7 桶
DefBuckets = []float64{0.05, 0.1, 0.25, 0.5, 1, 2.5, 5}

对延迟差异大的接口按业务分组使用 HistogramOpts.Buckets,别一套桶走天下。这一项降低 11 万 series。

4. recording rule 预聚合

看板上高频查询的 rate(xxx[5m]) 系列,提前算成聚合指标,把「逐条查询」变成「查一张表」:

groups:
  - name: api-aggregation
    interval: 30s
    rules:
      - record: job:http_request_duration_seconds:p95
        expr: histogram_quantile(0.95, sum by (job, le) (rate(http_request_duration_seconds_bucket[5m])))
      - record: job:http_requests:rate5m
        expr: sum by (job) (rate(http_request_requests_total[5m]))

查询耗时从 11s 降到 180ms,同时 TSDB 只需要保留聚合后的低基数结果。

四、效果与固化

指标 治理前 治理后
活跃 series 121 万 18 万
RSS 内存 28 GB 7.2 GB
rate 查询 P99 11 s 180 ms
压缩耗时 40 min+ 6 min

最后把「基数」纳入上线准入:CI 里跑一次 promtool check metrics,业务新增指标必须过基数评审;同时给 scrape_samples_scraped 配阈值告警,单 target 超过 5000 样本立即通知。

基数是设计问题,不是容量问题。加内存只能推迟爆掉的时间,砍基数才能根治。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

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

全部回复

上滑加载中

设置昵称

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

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

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