relabeling · Prometheus 出了名的强大与烧脑
relabeling 是「发现的目标」和「实际抓的目标」之间那台可编程的机器。这一章读 model/relabel 的 11 种 action、讲清那个统一的四步流水线心智模型,以及两个 relabel 阶段的关键区别——它同时也是控制基数最有力的工具。
relabeling · Prometheus 出了名的强大与烧脑
服务发现吐出一堆带着 __meta_* 标签的目标,但“发现的”和“该抓的”往往不是一回事:你可能只想抓带某个注解的 pod、想把 K8s 的 namespace 变成指标标签、想丢掉某些没用的指标。干这活的是 relabeling——Prometheus 出了名的强大、也出了名的让人头疼的机制。
一台可编程的标签机器
统一的四步心智模型
看 Config 结构(真实源码 model/relabel/relabel.go:86),字段本身就说明了流程:
type Config struct {
// 从哪些标签取值,按 Separator 拼接
SourceLabels model.LabelNames `yaml:"source_labels,flow,omitempty"`
// 拼接时用的分隔符(默认 ";")
Separator string `yaml:"separator,omitempty"`
// 拿拼接结果去匹配这个正则
Regex Regexp `yaml:"regex,omitempty"`
// hashmod 用的模数
Modulus uint64 `yaml:"modulus,omitempty"`
// replace 时,结果写到哪个标签
TargetLabel string `yaml:"target_label,omitempty"`
// 替换模板(可用 $1 $2 引用正则捕获组)
Replacement string `yaml:"replacement,omitempty"`
// ...Action
}每一条 relabel 规则都是同样的四步:
记住这四步,所有 relabel 规则都是它的实例化。 举个最常见的例子——“只抓带 prometheus.io/scrape: true 注解的 pod”:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] # ① 取这个标签的值
regex: "true" # ② 匹配 "true"
action: keep # ③ 匹配则保留,否则丢弃目标再比如“把 K8s namespace 变成指标上的 namespace 标签”:
- source_labels: [__meta_kubernetes_namespace] # ① 取值
action: replace # ③ 替换
target_label: namespace # ④ 写到 namespace 标签(没写 regex 时默认是 (.*),replacement 默认是 $1,所以就是原样拷贝。)
11 种 action
源码 model/relabel/relabel.go:46 列出了全部 action:
| action | 干什么 | 实战用途 |
|---|---|---|
replace | 正则替换后写入 target_label(默认 action) | 最常用:改写 / 拷贝标签 |
keep | 不匹配就丢弃目标 | 只抓我想抓的 |
drop | 匹配就丢弃目标 | 排除我不想抓的 |
labelmap | 按正则批量拷贝标签名 | 把所有 __meta_*_label_* 一次性变成指标标签 |
labeldrop | 丢掉匹配的标签 | 控基数:删掉没用的高基数标签 |
labelkeep | 只保留匹配的标签 | 白名单式清理 |
hashmod | 取哈希取模写入标签 | 分片:多个 Prometheus 各抓一部分 |
keepequal | 两个标签不相等就丢 | 少见 |
dropequal | 两个标签相等就丢 | 少见 |
lowercase / uppercase | 大小写转换 | 规范化 |
hashmod 值得单说——它是 Prometheus 水平分片的官方解法。 第 1 章说过 Prometheus 刻意单机自足,那目标太多一台抓不完怎么办?分片:
- source_labels: [__address__]
action: hashmod
modulus: 4 # 分 4 片
target_label: __tmp_shard
- source_labels: [__tmp_shard]
regex: "0" # 这台只抓第 0 片(其他 3 台分别配 1/2/3)
action: keep哈希保证同一个目标永远落在同一片,4 台 Prometheus 各抓 1/4、互不重叠也不遗漏。注意这仍然不是“分布式 Prometheus”——4 个实例彼此完全不知道对方存在,只是各自被配置成抓不同的子集。全局查询交给上层的 Thanos/Mimir。保持核心简单、复杂性推到外层,又一次。
两个阶段:relabel_configs vs metric_relabel_configs
这是最容易搞混、也最该搞清的一点:
relabeling 发生在两个完全不同的时机**,对应两个配置项——用错地方规则根本不生效。**
relabel_configs | metric_relabel_configs | |
|---|---|---|
| 时机 | 抓取前,对目标 | 抓取后,对每条指标 |
| 作用对象 | 目标的标签(含 __meta_*、__address__) | 抓回来的每条 series 的标签 |
drop 的效果 | 不抓这个目标(省网络+CPU+存储) | 抓了但丢掉这条指标(只省存储) |
| 典型用途 | 决定抓谁、设置 __address__/__metrics_path__ | 丢掉不需要的指标、删高基数标签 |
关键差异:relabel_configs 里 drop 掉的目标,压根不会被访问;metric_relabel_configs 里 drop 掉的指标,已经被抓回来解析过了。 所以:
- 想不抓某个目标 → 用
relabel_configs(便宜)。 - 想丢掉某个指标 → 只能用
metric_relabel_configs(因为指标是抓回来才知道的)。
另外 __meta_* 和 __ 开头的标签在 relabel_configs 之后就被丢弃了——它们只是 relabel 阶段的原料,不会进入最终 series。想留下某个 __meta_* 的值,必须在 relabel_configs 里显式把它 replace 到一个正常标签上。这是新手最常见的困惑:“我明明看到 SD 有这个标签,为什么指标上没有?”——因为你没把它拷贝出来。
实战:relabeling 是控基数最有力的工具
metric_relabel_configs 是你面对基数爆炸时的急救手段**——尤其当你改不了那个应用的代码时(第三方组件、云厂商 exporter)。** 两个高频救命姿势:
metric_relabel_configs:
# ① 丢掉整个没用的高基数指标
- source_labels: [__name__]
regex: "some_useless_high_cardinality_metric.*"
action: drop
# ② 保留指标,但删掉那个高基数标签(如带 UUID 的 path)
- regex: "user_id|request_id|session_id"
action: labeldrop第 ② 招尤其实用:很多 exporter 会吐出带 ID 的标签,让 series 数爆炸,但指标本身有用。labeldrop 把那个标签删掉,剩下的 series 会自动合并(标签少了,原本不同的 series 变成同一条)。
但要注意一个陷阱:labeldrop 后如果多条 series 塌缩成同一条,会产生“重复样本”错误(同一时刻同一 series 两个值)。所以删标签前要确认:删掉它之后,剩下的标签组合仍然唯一。如果不唯一,你需要的其实是在源头聚合,而不是 relabel。
小结与下一章
relabeling 是服务发现与抓取之间那台可编程的标签机器——它让 Prometheus 能适配千奇百怪的环境而核心不改。抓住统一的四步模型就不烧脑:① source_labels 取值按 separator 拼接 → ② 匹配 regex → ③ 按 action 决策 → ④ 写 target_label 或丢弃。11 种 action(model/relabel/relabel.go:46)里最常用 replace(默认)/keep/drop/labelmap/labeldrop,而 hashmod 是官方的水平分片解法(多实例各抓一片,彼此仍互不知情)。两个阶段务必分清:relabel_configs(抓取前、对目标,drop 就不访问)vs metric_relabel_configs(抓取后、对每条指标,drop 只省存储);__meta_* 标签在第一阶段后即丢弃,想留必须显式 replace 出来。实战上 metric_relabel_configs 是基数急救手段(drop 整个指标 / labeldrop 删高基数标签),但注意标签塌缩会引发重复样本——根治永远在埋点那一刻。
目标定了、标签改好了,真正的抓取循环怎么跑?下一章收尾第 1 部分。👉 抓取循环。
参考资料
- [1] Prometheus 源码
model/relabel/relabel.go(Config:86、11 种Action:46、Process实现)。 - [2] Prometheus 官方文档:Configuration —
<relabel_config>、metric_relabel_configs。 - [3] 关联服务发现的
__meta_*标签、基数控制。