TL;DR
- 高基数(High Cardinality)问题的核心不是 sample 数量大,而是 Time Series(时间序列)组合数失控。
- 判断一个 label 是否适合进入 Prometheus,关键不在于“值很多”,而在于它是否 有上界、可估算、可聚合。
request_id、trace_id、session_id、user_id、pod_uid、container_id这类 label 往往不是“高基”,而是接近无上界,应优先排除在指标体系之外。- 排查高基数时,不能只看
Head Series,还要同时看Series Churn,即单位时间新增和淘汰的时序速率。 - 在 Kubernetes / Agent 场景中,
node、namespace、pod、agent_id往往属于高基但可控;请求级、瞬态实例级 label 才是更常见的风险源。 - Prometheus 适合聚合统计,不适合明细检索。需要保留请求明细、用户明细或事件明细时,应优先考虑日志、Tracing 或 OLAP 链路。
- 一条经验结论可以直接记住:凡是可能“按请求生成新值”的 label,默认都不应该进入 Prometheus。
Prometheus 的高基数(High Cardinality)问题,是很多团队在监控系统规模扩大后最常遇到的稳定性问题之一。
很多 Prometheus OOM、查询变慢、监控系统不稳定的根因,并不是采样频率,而是 Time Series 组合数失控。
本文从 TSDB 原理出发,系统解释 High Cardinality 的形成机制,并给出 Kubernetes 与 Agent 场景下的工程治理方法。
问题定义:什么是高基数
在 Prometheus 中,一条 Time Series(时间序列) 由指标名和一组标签唯一确定:
series = metric_name + label_set
例如:
http_requests_total{method="GET",status="200",instance="api-1"}
只要 label_set 中任意一个值不同,就会形成新的 Time Series。
这里的关键概念是 Label Cardinality(标签基数)。
它表示某个 label 的不同取值数量。
例如:
method = {GET, POST} -> cardinality = 2
status = {200, 404, 500} -> cardinality = 3
instance = 1000 台实例 -> cardinality = 1000
单个 label 的基数高,并不一定构成问题。
真正的风险来自多个维度叠加后的乘法效应,也就是 Series Explosion(时序爆炸)。
如果一个指标同时带有以下标签:
method = 2
status = 5
pod = 3000
instance = 1000
user_id = 1000000
那么理论上的时序数量大致为:
2 x 5 x 3000 x 1000 x 1000000
这已经超出任何常规 Prometheus 实例可以承载的范围。
Series Explosion:一个更贴近工程现场的计算示例
假设某个 Kubernetes 集群中有一组对外 API 服务,规模如下:
200个 Pod- 每个 Pod 暴露 1 组 HTTP 请求指标
method维度取值4个status维度取值8个route模板60个
如果指标设计是合理的:
http_requests_total{method, status, route, pod}
那么这一类指标的时序规模大致为:
200 x 4 x 8 x 60 = 384000 series
这个数量不算低,但它仍然属于可估算、可拆分、可治理的范围。
如果同一类指标额外引入了 user_id,并且活跃用户规模按 500000 估算,那么规模会变成:
200 x 4 x 8 x 60 x 500000 = 192000000000 series
这里的问题不在于 user_id 这个字段“多了一个”,而在于它把一个原本可聚合的问题,变成了一个几乎无上界的明细建模问题。
因此,高基数问题不应该理解为“标签多了几个”,而应理解为:
某个本该用于聚合统计的指标,被引入了不适合做聚合的维度。
原理:Series、Label、Inverted Index 与 Series Churn 的关系
Time Series 是如何写入 TSDB 的
Prometheus 的 TSDB(时序数据库)在接收 sample 时,核心流程可以简化为:
sample
-> normalize labels
-> hash(label set)
-> lookup or create series
-> append sample to chunk
-> update index metadata
也可以用更接近内部结构的方式表示为:
+--------+ +------------------+ +-----------------+ +---------------+ +--------------+ +-----------------------+
| sample | -> | normalize labels | -> | hash(label set) | -> | create series | -> | append chunk | -> | update inverted index |
+--------+ +------------------+ +-----------------+ +---------------+ +--------------+ +-----------------------+
如果按时序写入路径展开,也可以表示为:
sample
│
normalize labels
│
hash(label set)
│
lookup / create series
│
append chunk
│
update inverted index
如果 sample 命中了已有的 Time Series,Prometheus 主要做的是追加写入。
如果出现了新的 label_set,Prometheus 就必须创建新的 series 元数据,并更新索引结构。
Prometheus 的资源消耗主要来自 Time Series 数量和 Series Churn,而不是 sample 数量。
因此,Prometheus 的成本不只由 sample 数决定,还直接取决于:
- 当前活跃 Time Series 数量
- 新建 Time Series 的频率
- label 组合的复杂度
Inverted Index 为什么会被高基数放大
Prometheus 查询依赖 Inverted Index(倒排索引)。
可以粗略理解为:
method="GET" -> series1, series2, series3
status="500" -> series2, series8
pod="api-1" -> series1, series2
查询时,Prometheus 需要根据多个 label matcher 在这些 posting list 上做过滤和求交。
这意味着高基数会同时放大两类成本:
- 写入时:更多 series 元数据、更多 label 存储、更多索引项
- 查询时:更大的 posting list、更高的求交和扫描成本
很多团队只关注“磁盘能不能放下”,但 Prometheus 更先遇到的问题通常是:
- Head Block 元数据驻留内存上升
- 倒排索引维护成本增加
- 查询延迟变大
- CPU 被查询和压缩任务拉高
Head Series 与 Series Churn 要分开看
在排查时,至少要区分两个概念:
- Head Series:当前活跃的 Time Series 数量
- Series Churn:单位时间内新建和淘汰的 Time Series 速率
两者不是一回事。
如果系统的 Head Series 很高,说明当前常驻的时序很多。
如果系统的 Series Churn 很高,即便总量没有立刻失控,也可能因为频繁创建和淘汰时序而产生额外压力。
例如下面两种情况:
-
资源级 label 很多,但系统规模稳定
结果往往是高基但可控。 -
每个请求都带
request_id或trace_id
结果往往是持续创建新 series,形成明显的 churn。
在工程上,第二类问题通常更危险,因为它往往意味着基数没有天然上界。
危害:高基数为什么会导致内存、索引、查询和 OOM 问题
高基数问题在 Prometheus 中通常沿着下面这条链路放大:
- 新的 label 组合不断进入系统
- Time Series 数量上升
- Head Series 与索引元数据占用更多内存
- 查询扫描范围扩大,CPU 与延迟上升
- 在持续增长或 churn 很高时,实例变得不稳定,甚至 OOM
具体表现通常包括:
prometheus_tsdb_head_series持续上涨prometheus_tsdb_symbol_table_size_bytes增长明显process_resident_memory_bytes与go_memstats_heap_alloc_bytes上升- 查询变慢,Grafana dashboard 响应时间拉长
- 抓取、压缩、规则评估相互竞争资源
需要强调的是,Prometheus 的问题并不总是因为“采样太密”。
在很多实际场景里,真正的瓶颈来自:
- 标签组合过多
- 新建时序过快
- 把明细维度误放进了聚合系统
官方建议与工程理解
Prometheus 官方长期建议避免把高基数字段直接作为 label。相关文档可直接参考:
Metric and label naming: prometheus.io/docs/practi…Instrumentation best practices: prometheus.io/docs/practi…
工程上更值得关注的不是“背结论”,而是理解这些建议背后的系统成本。
这条建议在工程上应理解为两层含义:
第一层:不要把无上界输入直接映射为 label
典型风险字段包括:
request_idtrace_idspan_idsession_iduser_iddevice_idorder_idcontainer_idpod_uid
这些字段的问题不只是“值多”,而是:
- 取值往往来自请求或运行时对象
- 无法提前估算真实上界
- 很容易持续产生新值
- 对 Prometheus 的聚合分析帮助有限
第二层:高基数不等于一定错误
以下标签在很多系统里本身也是高基数:
instancenodepodnamespaceagent_id
但它们通常具备几个特征:
- 与基础设施规模相关
- 具备可估算上界
- 在定位问题时有明确价值
因此,真正需要区分的是:
- 有上界的高基
- 无上界的高基
前者未必错误,后者才是 Prometheus 体系里更常见的系统性风险。
哪些 label 可以接受,哪些必须避免
下面这张表更适合作为工程决策表,而不是“绝对规则表”。
| label 类型 | 典型例子 | 是否建议进入 Prometheus | 原因 | 更合适的替代方案 |
|---|---|---|---|---|
| 资源级 label | instance、namespace、pod、node、agent_id | 通常建议 | 与集群或节点规模相关,通常存在可估算上界,且对定位问题有价值 | 保留,但控制粒度;必要时按集群/业务拆分采集 |
| 业务聚合级 label | method、status、route | 建议 | 基数通常较低,天然适合聚合统计和告警 | 继续保留,并使用模板化 route、状态码分组 |
| 请求级 label | request_id、trace_id、span_id | 不建议 | 随请求持续生成新值,Series Churn 高,几乎没有可控上界 | 放入 Tracing、日志或事件流 |
| 用户级 label | user_id、device_id、session_id | 不建议 | 取值空间大且来自业务明细,不适合聚合监控 | 用用户分层、租户分组、region 等聚合维度替代 |
| 运行时实例级 label | container_id、pod_uid | 通常不建议 | 生命周期短、变化频繁,容易造成高 churn,且往往与 pod / container 名称重复 | 保留 pod、namespace、container 等稳定维度即可 |
这张表背后的判断标准只有三个:
- 是否有明确上界
- 是否能服务于聚合统计
- 是否会因请求或运行时对象变化而持续产生新值
检测方法:PromQL、Dashboard、TopN 与 Churn 观察
高基数问题不适合等到 OOM 再排查。
更稳妥的做法是把它作为常规容量治理的一部分。
1. 先看总量:Head Series
prometheus_tsdb_head_series
这条指标反映当前活跃时序规模。
它不是根因定位工具,但可以帮助判断系统是否已经逼近容量边界。
建议同时观察:
prometheus_tsdb_head_chunks
prometheus_tsdb_symbol_table_size_bytes
process_resident_memory_bytes
如果这些指标同步上升,通常说明:
- 活跃时序在增长
- 标签元数据和索引负担在变重
- 实例内存压力正在增加
2. 再看增速:新建 Series 速率
rate(prometheus_tsdb_head_series_created_total[5m])
如果该值在没有业务扩容、没有大规模变更的情况下持续偏高,需要重点怀疑:
- 引入了无上界 label
- 某类 exporter 输出了异常维度
- 某个 label 的取值空间发生了非预期膨胀
对应地,也建议同时看:
rate(prometheus_tsdb_head_series_removed_total[5m])
如果创建和移除都很高,说明存在明显的 Series Churn。
如果创建高、移除低,说明时序总量还在积累。
3. 定位问题指标:TopN Series
在很多环境里,第一步先做 TopN 排查就足够有效:
topk(20, count by (__name__)({__name__=~".+"}))
这条查询适合快速找出“当前时序规模最大的指标名”。
如果环境中支持额外的 cardinality 分析工具,还应进一步展开:
- 哪些 label 贡献了最多组合
- 哪些指标在过去一段时间内 churn 明显升高
- 哪些 job / target 带来了新时序增长
4. 检查某个维度的 Cardinality
例如查看 instance 数量:
count(count by (instance) (up))
查看某个业务指标下 pod 维度规模:
count(count by (pod) (http_requests_total))
查看 route 维度规模:
count(count by (route) (http_request_duration_seconds_count))
这些查询并不复杂,但足以帮助判断:
- 某个 label 是否超出系统规模预期
- 某个业务是否引入了不合理维度
5. 建立专门的 Cardinality Dashboard
建议为 Prometheus 实例单独建设一个 dashboard,最少包含:
- Head Series
- Series Created Rate
- Series Removed Rate
- Symbol Table Size
- RSS / Heap
- 慢查询趋势
如果系统规模较大,还建议按以下维度拆开观察:
- 按 job 的抓取规模
- 按业务域的指标数量
- 按集群或环境的 series 分布
高基数问题一旦走到 OOM 阶段,处理成本就已经偏高。
更合理的方式是在它还只是“曲线开始变陡”时发现它。
一个更适合落地执行的高基数排查路径如下:
发现监控异常
│
Head Series 是否异常
│
查看 Series Created Rate
│
定位 TopN 指标
│
检查 label cardinality
│
确认是否存在 request_id / user_id / container_id 等无界 label
常见高基数事故案例
案例一:把 request_id 直接打进请求指标
典型形式:
api_request_total{method="GET",status="500",request_id="req-xxx"}
事故模式通常是:
- 业务请求量本身不算异常
- Prometheus 抓取仍然成功
- 但
Head Series和Series Created Rate持续上升 - 最终内存压力和查询性能同时恶化
这类问题的根因通常不是“流量太大”,而是指标把每个请求都建模成了新的 Time Series。
案例二:把原始 URL 当作 path label
典型形式:
http_request_duration_seconds{path="/api/orders/123456"}
如果 URL 中包含订单号、用户 ID、文档 ID 或其他业务主键,path 的 cardinality 会随业务数据规模同步增长。
这类事故的典型特征是:
- 整体 QPS 没明显变化
- 但某几个业务接口的指标规模异常大
route模板本可稳定聚合,却被原始路径替代
案例三:把 pod_uid / container_id 这类瞬态实例 ID 暴露为 label
典型形式:
runtime_metric{pod_uid="...",container_id="..."}
这类问题常见于 Kubernetes 生态中的自定义 exporter 或中间层组件。
问题不一定会立刻表现为超大 Head Series,但往往会表现为:
- 实例滚动升级后
Series Churn明显升高 - Prometheus 内存和 WAL 压力持续波动
- 相同语义的资源被重复编码为不同的瞬态 ID
这些案例的共性都很明确:
Prometheus 被拿来承接明细主键或瞬态对象,而不是承接聚合维度。
Kubernetes / Agent 场景分析
Kubernetes 场景里,高基数判断经常被简单化为“pod 多,所以天然会炸”。
这个判断不准确。
为什么 agent_id 往往属于“高基但可控”
在 Node Agent、日志 Agent、eBPF Agent、宿主机采集器这类系统里,agent_id 往往对应一台机器、一个节点或一个固定部署单元。
例如:
agent_metric{agent_id="node-172-20-10-12"}
它的基数可能很高,但通常仍然可接受,因为:
- 基数和节点规模直接相关
- 上界可以通过集群容量规划估算
- 对故障定位和实例级观测有实际价值
这属于典型的有上界的高基。
为什么 pod / namespace / node 通常可接受
这类 label 的共同点是:
- 来自稳定的资源模型
- 与 Kubernetes 对象层级一致
- 在调度、容量和故障定位中具有直接意义
例如:
container_cpu_usage_seconds_total{namespace="prod",pod="api-7d8b9",node="worker-12"}
这里的 namespace、pod、node 虽然可能数量不少,但通常仍是合理维度。
因为它们反映的是资源实体,而不是请求明细。
为什么 pod_uid / container_id / request_id / trace_id 危险
这些 label 的问题在于它们往往同时具备以下属性:
- 生命周期短
- 变化频繁
- 与请求或瞬态实例绑定
- 容易产生新的唯一值
例如:
request_total{pod_uid="...", container_id="...", request_id="...", trace_id="..."}
这类指标把基础设施层和请求层的明细维度混在了一起。
它们通常会带来两个后果:
- Head Series 增长失控
- Series Churn 异常升高
这是比“pod 数量多”更常见、也更危险的问题。
高基不等于一定错误,关键在于是否有上界
在 Kubernetes / Agent 场景中,最实用的判断方式不是问“这个 label 高不高”,而是问:
- 它是否与资源规模直接相关?
- 它能否提前估算上界?
- 它是否有稳定的聚合价值?
- 它是否会按请求或实例重建而不断产生新值?
如果前 3 个答案偏正面,第 4 个答案是否定的,那么即使它是高基,也通常是可接受的。
反之,即便当前数量看起来不大,也可能是一个未来会失控的风险源。
治理方法:指标设计、Label 收敛、采集侧处理与架构隔离
高基数治理不应停留在“出事后删标签”。
更稳妥的做法是从设计、采集、运行和架构几个层面同时建立边界。
1. 指标设计:先判断它是不是一个聚合维度
Prometheus 适合描述:
- 某类请求的总量
- 某类错误的比例
- 某类延迟的分布
- 某类实例的资源状态
它不适合描述:
- 某一个请求
- 某一个用户
- 某一个 session
- 某一个 trace
如果一个字段本质上是“明细主键”,它通常就不应该成为 label。
2. 治理前后对比
对比一:原始 URL 改为 route 模板
Before:
http_request_duration_seconds{
method="GET",
path="/api/orders/123456/items/9988"
}
After:
http_request_duration_seconds_bucket{
method="GET",
route="/api/orders/:id/items/:item_id",
le="0.5"
}
为什么 After 更适合 Prometheus:
- 原始 URL 往往包含业务主键,基数随数据规模增长
- route 模板有稳定上界,更适合聚合统计
- histogram bucket 能表达延迟分布,而不需要保留请求明细
这里的核心不是“少几个 label”,而是把指标从明细表达改为聚合表达。
对比二:把 request_id / user_id 从 metrics 中移出
Before:
api_request_total{
method="POST",
status="500",
request_id="req-9f8a",
user_id="u-123456"
}
After:
api_request_total{
method="POST",
status="500",
tenant="enterprise",
error_class="upstream_timeout"
}
配套做法:
- 把
request_id、trace_id放入 tracing 或 structured logging - 把
user_id替换为租户、地域、套餐等可聚合维度
为什么 After 更适合 Prometheus:
- 指标保留了聚合分析和告警需要的维度
- 明细主键不再造成无上界 Time Series 膨胀
- 问题定位可以通过 metrics -> logs / traces 的联动完成
Prometheus 适合聚合统计,不适合明细检索。
这条边界一旦模糊,系统就会很快被高基数击穿。
3. 采集侧治理样例
如果某些组件已经输出了不合理标签,优先考虑在采集侧进行收敛,而不是把坏数据先写入 TSDB。
示例一:直接删除高风险 label
scrape_configs:
- job_name: app
static_configs:
- targets: ["app:9090"]
metric_relabel_configs:
- action: labeldrop
regex: "request_id|trace_id|span_id|session_id|pod_uid|container_id"
适用场景:
- exporter 或业务组件短期内难以改造
- 已确认这些标签不参与聚合分析
- 需要先阻断高基数继续扩散
示例二:保留必要标签,丢弃无界标签
scrape_configs:
- job_name: gateway
kubernetes_sd_configs:
- role: pod
metric_relabel_configs:
- source_labels: [__name__]
regex: "http_request_duration_seconds_bucket|http_requests_total"
action: keep
- action: labelkeep
regex: "__name__|job|instance|namespace|pod|service|method|status|route|le"
- action: labeldrop
regex: "request_id|trace_id|user_id|device_id|session_id|pod_uid|container_id"
这个配置的意图是:
- 只保留核心 HTTP 指标
- 只保留聚合和定位必须的标签
- 主动丢弃无界或瞬态维度
示例三:对问题指标直接丢弃
scrape_configs:
- job_name: legacy-app
static_configs:
- targets: ["legacy-app:9100"]
metric_relabel_configs:
- source_labels: [__name__]
regex: ".*_by_user_.*|.*_by_session_.*"
action: drop
适用场景:
- 业务组件暴露了明显不适合 Prometheus 的指标
- 这些指标短期内无法重构
- 继续保留只会增加系统负担
采集侧治理的原则很简单:
不让无界 label 穿透到 TSDB。
4. 运行侧治理:把容量边界显式化
除了删 label,更关键的是建立容量边界:
- 单实例允许的 Head Series 范围
- 可接受的 Series Created Rate
- RSS / Heap 告警阈值
- 慢查询告警阈值
- 新业务接入前的 series 规模评估流程
如果没有这些边界,Prometheus 的容量会在业务增长过程中被隐式消耗,直到某次上线或扩容后突然失控。
5. 架构隔离:让 Prometheus 只承载适合它的数据
对高基数治理更成熟的团队,最终都会走向数据分层。
典型思路如下:
Agent / Exporter
-> Gateway / Remote Write
-> 聚合指标 -> Prometheus / VictoriaMetrics
-> 明细事件 -> Kafka / OLAP / Logs / Trace Backend
如果只看主监控查询链路,也可以简化为:
+-----------+ scrape +------------+ remote_write +-----------------+ query +---------+
| Exporter | -----------> | Prometheus | ---------------> | VictoriaMetrics | ---------> | Grafana |
+-----------+ +------------+ +-----------------+ +---------+
按组件链路展开,也可以简化理解为:
Exporter
-> Prometheus
-> Remote Write
-> VictoriaMetrics
-> Grafana
其核心原则不是“统一进一个系统”,而是:
- 聚合指标走稳定、低延迟、低基数链路
- 明细事件走允许延迟、允许大规模扩展的分析链路
- 让主监控系统服务于告警、趋势和容量判断,而不是承接明细检索
如果把治理动作串成一条工程流程,通常会更接近下面这个顺序:
指标设计
│
label 上界评估
│
Prometheus 接入评审
│
采集侧 labeldrop
│
cardinality dashboard 监控
容量估算:在接入前先算一遍 Series 规模
高基数问题本质上是规模问题,因此容量估算应当尽量前置。
一个实用的粗估算方法是:
总 series 规模 ~= 指标数 x 实例数 x 关键 label 组合数
例如某类 agent 场景:
50000个 agent- 每个 agent 暴露
200个核心指标 - 每个指标平均形成
5组主要标签组合
那么粗略规模大致为:
50000 x 200 x 5 = 50000000 series
这个数字并不要求绝对精确,但它足以帮助回答几个工程问题:
- 是否需要对 Prometheus 做分片
- 是否要按环境或业务拆实例
- 是否需要 remote write 或长期存储后端
- 哪些维度必须在接入前做收敛
如果一个新业务上线前连数量级都没有估算,Prometheus 的容量就只能依赖线上试错。
Prometheus vs VictoriaMetrics
这个问题更适合从“职责分工”而不是“谁绝对更好”来理解。
Prometheus 的优势通常在于:
- 生态成熟
- 拉取模型和规则体系完善
- 与 Alertmanager、Grafana 及大量 exporter 协作紧密
VictoriaMetrics 在一些场景下通常更适合作为大规模承载层,尤其是在:
- 大规模写入
- 存储压缩效率
- 长期存储成本
- 水平扩展能力
这些方面,经常会体现出更好的工程适配性。
但这并不意味着换了后端就可以忽略高基数治理。
更准确的表述应是:
- 更适合大规模承载的存储后端,可以提高系统容忍度
- 但它不能替代正确的指标设计和 label 边界控制
很多生产环境会采用组合架构:
Prometheus 负责抓取、规则评估和告警
VictoriaMetrics 负责长期存储或更大规模指标承载
这是一种常见实践,但不是唯一正确答案。
是否采用该组合,取决于团队规模、查询模型、成本目标和运维能力。
总结
高基数问题的工程本质,可以归纳为三句话:
- Prometheus 的容量压力主要受 Time Series 数量和变化速率驱动,而不只是 sample 数量。
- 高基数不等于一定错误,真正需要优先治理的是无上界、不可聚合、持续产生新值的 label。
- 有效治理依赖完整方法链条:设计约束、采集收敛、运行监控、容量评估和架构分层。
如果把请求主键、用户主键、瞬态实例 ID 直接写进 metrics,Prometheus 最终承受的不是“更多监控”,而是“不适合它处理的数据模型”。
因此更稳妥的实践不是追求“把所有数据都接进去”,而是明确边界:
- 哪些维度属于聚合统计
- 哪些维度属于事件明细
- 哪些数据应进入 Prometheus
- 哪些数据应进入日志、Tracing 或 OLAP 系统
这类边界一旦明确,Prometheus 的稳定性、容量规划和故障定位效率都会明显改善。
附录:常用 PromQL 与上线检查清单
常用 PromQL
1. 查看 TopN Series 指标
topk(20, count by (__name__)({__name__=~".+"}))
用途:
- 快速定位当前时序规模最大的指标名
1.1 查看 job 维度的 Series 分布
topk(20, count by (job)({__name__=~".+"}))
用途:
- 快速判断哪些
job正在贡献最多的 Time Series - 适合先从抓取源头定位问题范围
2. 查看新 Series 速率
rate(prometheus_tsdb_head_series_created_total[5m])
用途:
- 观察是否正在持续生成新的 Time Series
3. 查看某个维度的 Cardinality
count(count by (instance) (up))
count(count by (pod) (http_requests_total))
count(count by (route) (http_request_duration_seconds_count))
count(count by (namespace) (up))
用途:
- 判断某个 label 的实际取值规模是否符合预期
- 对指定维度做 cardinality 粗查时,可将
namespace替换为目标 label
4. 发现 Churn 异常的查询思路
rate(prometheus_tsdb_head_series_created_total[5m])
-
rate(prometheus_tsdb_head_series_removed_total[5m])
以及:
rate(prometheus_tsdb_head_series_created_total[5m])
配合:
prometheus_tsdb_head_series
用途:
- 判断系统是在单纯扩容,还是在异常创建大量新时序
- 观察新增与淘汰是否同时偏高,从而识别高 churn
上线检查清单
- 这个 label 是否有天然上界,且上界是否可以估算?
- 它是否可能按请求、按用户、按 session 或按 trace 持续生成新值?
- 它是否能被
route、bucket、status、tenant、region等聚合维度替代? - 新业务接入前,是否做过 series 规模估算?
- 是否已经建设
Head Series与Series Created Rate的监控和告警? - 是否有专门的 cardinality dashboard 用于日常巡检?
- 是否评估过该指标更适合进入 metrics、logs、tracing 还是 OLAP?
- 是否在采集侧配置了必要的
metric_relabel_configs、labeldrop或drop规则? - 如果该指标来源于 Kubernetes 或 Agent,是否确认它属于“有上界的高基”而不是“无上界的高基”?
- 如果未来规模扩大 2 到 5 倍,这组指标是否仍在当前 Prometheus 实例的容量边界内?
这份清单的目标不是让指标体系变得保守,而是让每一个新增维度都经过基本的工程判断。