高基数是什么
序列数由指标名与标签取值的组合决定:一个标签每多一种取值,序列数就按倍数增长。把用户标识、完整路径、请求编号这类近乎唯一的取值放进标签,会让序列数随流量膨胀,代价直接体现在内存、磁盘与查询延迟上。
为什么伤害这么大
每条序列都要在内存里维护索引与近期样本,序列数增长意味着内存与磁盘同时吃紧,查询时要扫描的序列也成倍增加。高基数指标的危害具有滞后性:写入时看起来一切正常,等到查询变慢或进程被拖垮时才暴露,此时清理成本已经很高。
基本信息
| 影响面 | 内存占用、存储体积、查询延迟同时恶化 |
|---|---|
| 常见来源 | 用户或会话标识、未归一化的路径、动态错误信息 |
| 治理时机 | 采集端丢弃最省成本,事后清理代价大 |
| 观察指标 | 当前序列总数与按指标名排序的序列数 |
典型使用场景
- 容量评估:把握序列总数的增长趋势,提前发现异常指标
- 埋点评审:上线前检查新指标的标签取值上限
- 采集端治理:丢弃无用指标与高基数标签,减轻存储压力
- 路径归一化:把带参数的路径模板化,让接口维度可控
- 故障后复盘:定位是哪个版本或哪个服务引入了标签爆炸
定位高基数的常用查询
定位高基数的常用查询
# 序列数靠前的指标
topk(10, count by (__name__) ({__name__=~".+"}))
# 某个标签的基数
count(count by (path) (http_requests_total))
# 当前序列总量
prometheus_tsdb_head_series高基数的常见来源
| 来源 | 为什么失控 | 替代做法 |
|---|---|---|
| 用户或会话标识 | 取值随用户数线性增长 | 放到日志或链路里检索 |
| 未归一化路径 | 每个资源 ID 都是一条新序列 | 改写为路径模板 |
| 动态错误信息 | 错误文本本身近乎唯一 | 按错误类型粗分类 |
| 时间戳类标签 | 每次请求都产生新取值 | 直接用样本时间戳 |
治理手段
| 手段 | 作用 | 代价 |
|---|---|---|
| 采集端丢弃指标 | 直接减少入库量 | 丢弃后不可追溯 |
| 删除高基数标签 | 保留指标但降低维度 | 该维度上无法再筛选 |
| 路径归一化 | 把高基数维度变成可控枚举 | 需要改应用埋点 |
| 限制写入 | 保护服务端不被拖垮 | 会丢失部分数据 |
在采集端丢弃比事后治理更省成本:先加指标级别的重标记规则再观察序列数变化,比等到查询变慢才处理要划算得多。
基数不是越低越好:实例、服务、状态码这类维度是排障必需,治理的目标是剔除近乎唯一的取值,而不是把所有维度都删掉。