
监控系统开始变慢时,团队常先增加内存,却忽略了真正的放大器:标签。一个看似普通的 user_id,可能把一条指标扩成百万条时间序列。治理基数不是少采指标,而是让指标只承担聚合判断,把细节留给更合适的信号。
基数为什么会失控
Prometheus 用“指标名 + 完整标签集合”识别一条时间序列。标签取值组合越多,内存、索引、持久化与查询成本就越高。若某指标有 5 个方法、6 类状态、80 条路由和 20 个实例,理论上最多会形成:
1 | 5 × 6 × 80 × 20 = 48,000 条时间序列 |
实际维度可能相关,因此乘积只是上界;但用户 ID、请求 ID、原始 URL 等无界值会持续制造新组合。经典直方图还会为每个标签组合产生多条 bucket 以及 _sum、_count,放大尤其明显。

| 标签 | 建议 | 原因 |
|---|---|---|
method、status_class |
保留 | 枚举有限,便于聚合 |
规范化的 route |
谨慎保留 | 路由数量应有明确上限 |
user_id、request_id |
禁止 | 取值近乎无界 |
| 含参数的原始路径 | 禁止 | 每个资源都可能生成新序列 |
埋点时应记录 route="/orders/:id",而不是 /orders/84721。判断某字段是否适合作标签,可以问一句:半年后它可能出现多少种值?回答不出上限,就不应进入指标。
先找到增长源
先观察 prometheus_tsdb_head_series 的趋势,再用 TSDB 状态页查看高基数指标和标签。临时排查也可按指标名统计当前序列数;查询本身可能较重,应避开高峰并限制使用频率:
1 | topk(20, count by (__name__) ({__name__=~".+"})) |
发现异常指标后,回到发布记录与埋点代码,比较新增标签前后的序列增量。不要只看总量:实例扩容也会推高序列数,但增长应与实例数近似成比例;若流量不变却持续上升,通常是无界标签或不断出现的新路径。
让三类信号各司其职

指标适合回答“错误率是否升高”,日志适合查询某个用户或请求的事件,追踪适合还原一次调用链。需要关联时,在日志和追踪中保存请求 ID;指标只保留服务、规范化路由、结果类别等有界维度。不要为了从告警直接定位单个请求,把所有上下文塞进标签。
从源头修复并设置护栏
最有效的修复是在埋点端删除危险标签、规范化路由,并减少不必要的直方图桶。聚合规则能让看板更快,却不会删除已采集的原始序列,因此不能替代源头治理。
紧急止损时,可以在采集前丢弃明确无用的实验指标,并设置单次采集样本上限:
1 | scrape_configs: |
sample_limit 超限会使整次采集失败,它是保险丝而不是日常配额,必须同时告警。删除标签也要小心:不同序列去掉标签后可能发生碰撞,优先修改生产者或整条丢弃确认无用的指标。
把基数纳入变更评审
为关键指标维护一份简单清单:负责人、标签集合、每个标签的预期上限、预计组合数。新增标签时先在预发或少量实例启用,观察 Head Series、内存、WAL 写入和采集耗时,再逐步放量。
| 检查项 | 通过标准 |
|---|---|
| 标签边界 | 每个值域可解释、可估算 |
| 增量预算 | 新增序列没有超过团队预算 |
| 回滚手段 | 能关闭新指标或撤销新标签 |
| 责任归属 | 异常增长能找到维护者 |
基数治理的核心不是追求序列越少越好,而是让每条序列都有明确价值和成本边界。先修复一个增长最快的指标,再把预算检查放进埋点评审,通常比反复扩容更持久。