Prometheus 基数(cardinality)太高有什么危害?
更新时间:2026-09-19。短答页。基数是 Prometheus 生产事故的第一大原因:不是指标值太大,而是时间序列条数太多。
一句话回答
每条「指标名 + 一组标签取值」就是一条独立时间序列,序列数 ≈ 各标签取值数的笛卡尔积;把 user_id、request_id、IP、原始 URL 这类高取值维当标签,会让序列数爆炸,直接撑爆 Prometheus 的内存/磁盘、拖慢查询甚至 OOM。
怎么算出来的
bash
http_requests_total{method, route, code, instance}
method(2) × route(50) × code(8) × instance(100) ≈ 8 万条序列(可控)
错误示范:再加一个 user_id
× user_id(1000 万) → 数千亿条(直接炸)原始 URL 同理:/user/10086、/user/10087 每个用户一条,应在埋点处归一化成路由模板 /user/:id。
危害
- 内存暴涨:Prometheus 为每条序列维护索引和最近样本,高基数是 RSS 主因,极端触发 OOM、数据丢失。
- 磁盘/WAL 压力:每秒写入样本数随序列数线性上升,压缩、查询都变慢。
- 查询和看板超时:
sum by要扫描海量序列,Grafana 卡死。 - 告警评估变慢:规则组评估超时,触发/恢复延迟。
怎么发现
promql
# 序列数最多的指标名
topk(10, count by (__name__)({__name__=~".+"}))
# 某指标按高基标签展开看取值数量
count by (path)(http_requests_total)TSDB 状态页 / TSDB head、prometheus_tsdb_head_series 指标也能看总量趋势。
怎么治理
- 不该进标签的坚决不进:user_id、request_id、trace_id、email、原始 URL、完整错误消息。要分析单请求用日志/trace(带 trace_id),不是 metrics。
- 路由归一化:埋点/网关把
/user/123归并成/user/:id,查询参数不要进 path 标签。 - relabel 丢弃:抓取时用 metric_relabel_configs drop 掉无用或高基指标/标签。
- 控制 histogram bucket 数量:bucket 数也乘进基数,通常 10~20 个足够,别设上百个。
- recording rule 预聚合:高基数原始指标只短期保留,常用查询预算成低基数指标供看板和告警。
- 分级与分流:超大规模用 VictoriaMetrics/Thanos/Mimir 或把明细事件放日志系统。
坑
- 把「想按用户排查」当理由放进标签——明细排查看日志和追踪,指标只回答聚合问题。
- 上线新埋点不评估基数,一个 user_id 标签半夜把 Prometheus 打挂。
- 只盯指标条数不盯标签取值数,真正的爆炸藏在标签维度里。
标签与四种指标类型的正确用法见 Prometheus 数据模型。
总结
Prometheus 基数指时间序列条数,等于指标各标签取值数的笛卡尔积,把 user_id、request_id、IP、原始 URL 这类高取值维度做成标签会让序列数从几万膨胀到亿万级,引发内存磁盘暴涨、查询告警超时乃至 OOM;治理方法是只保留有限取值且确需聚合的标签、将路径归一化为路由模板、用 relabel 丢弃无用维度、精简 histogram bucket、用 recording rule 预聚合,并把单请求级排查交给带 trace_id 的日志与链路系统。