Grafana cluster变量出现Kafka垃圾值的排查与清理
记录时间:2026-08-08
环境:RKE 信创 ARM64 / kube-prometheus-stack / Prometheus 2.52 / VictoriaMetrics 集群 / Grafana
一、问题现象
Grafana 的 cluster 模板变量(Query type 为 Label values,查询 label_values(cluster))Preview 里冒出来 4 个值:
clusterA-prod-xc
clusterB-prod-xc
clusterA-kafka-cluster
{{ $labels.kafka_cluster }}
后两个明显是垃圾值。cluster 变量本应只包含真实集群标识(clusterA-prod-xc、clusterB-prod-xc),而且更诡异的是,在本地 Prometheus 里直接查这两个值,根本找不到对应序列。
二、排查过程
2.1 起因:对比 node-exporter 覆盖时发现
起因是某次对比核实 node-exporter 监控覆盖时,顺带看了下 cluster 变量,结果发现 Preview 里多了一堆垃圾值。
2.2 搜索 cluster 标签来源
全仓库搜 cluster 相关赋值,命中两处关键配置:
| 位置 | 内容 | 作用 |
|---|---|---|
clusterA-prod-xc-kube-prometheus-stack/values.yaml:165-166 |
externalLabels: cluster: "clusterA-prod-xc" |
clusterA(集群A)外部标签 |
clusterB-prod-xc-kube-prometheus-stack/values.yaml:163-164 |
externalLabels: cluster: "clusterB-prod-xc" |
clusterB(集群B)外部标签 |
rules/kafka/kafka-rules.yaml |
18 处 cluster: "{{ $labels.kafka_cluster }}" |
Kafka 告警规则 labels |
外部标签 cluster 只有两个合法值(clusterA / clusterB),而 kafka_cluster 标签来自两个 Kafka ServiceMonitor 的 relabeling:
kafka/helm/prod/kafka4.0/kafka-exporter-servicemonitor.yaml:73-74→kafka_cluster: clusterA-kafka-clusterclusterB-prod-xc-kube-prometheus-stack/other/kafka/kafka-sm.yaml:33→kafka_cluster: clusterB-kafka-ingest
2.3 最初的误判
最开始我直接怀疑是 kafka-rules.yaml 里那 18 处 cluster: "{{ $labels.kafka_cluster }}" 干的好事。但转念一想不对:这是告警规则输出给 Alertmanager 的标签,跟 Grafana 的 label_values 查询能有什么关系?不能想当然,得从机制上确认它到底影不影响。
2.4 核实机制:ALERTS 序列写入 TSDB
查 Prometheus 官方文档确认:告警处于 pending/firing 时,Prometheus 会生成名为 ALERTS 的合成时间序列并写入 TSDB,该序列的标签集包含规则 LABELS 子句定义的所有标签(不只是 alertname/alertstate)。
也就是说,告警规则的 labels 不只是发给 Alertmanager,同时会落进 TSDB 的 ALERTS 序列;label_values(cluster) 扫的是全序列,自然把它们收进来。
2.5 关键转折:Grafana 数据源其实是 VictoriaMetrics
本地 Prometheus 查不到,是因为 Grafana 连的根本不是它。证据有三:
values.yaml:174-177:PrometheusremoteWrite到http://prod.vm.example.com/insert/0/prometheus/(VictoriaMetrics)values.yaml:595-599:Grafana hostAliases 专门为prod.vm.example.com写了解析(指向10.x.x.x)- Preview 里同时有
clusterA-prod-xc和clusterB-prod-xc:只有 VM 汇总了两套 Prometheus 的 remoteWrite 数据,才会同时出现两个集群的 cluster 值;本地 Prometheus 只有 clusterA 一个
Grafana 数据源是在 UI 手动配置的(values.yaml:684-685 的 datasources.enabled: false,数据源存 MySQL),仓库里看不到,但 VM 域名写进 hostAliases 已经足以说明指向。
2.6 在 VM 中验证,确认根因
直接在 VM 里查 ALERTS 序列,结果证实了上面的判断:
表 1:cluster=clusterA-kafka-cluster 的 ALERTS
| alertname | alertstate | kafka_cluster | cluster |
|---|---|---|---|
| KafkaController频繁切换 | pending | clusterA-kafka-cluster | clusterA-kafka-cluster |
| KafkaBroker不可用 | pending | clusterA-kafka-cluster | clusterA-kafka-cluster |
| KafkaISR持续收缩 | firing | clusterA-kafka-cluster | clusterA-kafka-cluster |
这些告警的 expr 结果序列带 kafka_cluster 标签,模板 {{ $labels.kafka_cluster }} 渲染成功,得到实际值 clusterA-kafka-cluster。
表 2:cluster={{ $labels.kafka_cluster }} 字面量的 ALERTS
| alertname | alertstate | kafka_cluster | cluster |
|---|---|---|---|
| KafkaController数量异常 | pending | (空) | {{ $labels.kafka_cluster }} |
| Kafka集群节点存活数告警 | pending | (空) | {{ $labels.kafka_cluster }} |
这两条告警的 expr 是 sum by(systemName) (...) 聚合查询,聚合后 kafka_cluster 标签被丢弃,模板没有可引用的标签值,字面量 {{ $labels.kafka_cluster }} 原样进了 ALERTS 序列的 cluster 标签。
三、根因分析
根因链条如下:
kafka-rules.yaml 告警规则 labels 写 cluster: "{{ $labels.kafka_cluster }}"
↓ 告警 pending/firing
Prometheus 生成 ALERTS 合成序列写入 TSDB(带渲染后的 cluster 标签)
↓ remoteWrite 全部写入
VictoriaMetrics(prod.vm.example.com)
↓ Grafana label_values(cluster) 扫描全序列
cluster 变量出现 clusterA-kafka-cluster / {{ $labels.kafka_cluster }} 两个垃圾值
另外两个现象的解释:
- 为什么会有两种垃圾值形态:取决于告警 expr 是否保留
kafka_cluster标签。保留则渲染成实际值;被sum by(systemName)等聚合丢弃则保留字面量。 - 为什么 externalLabels 没兜底:externalLabels 本会把
cluster: "clusterA-prod-xc"加到 ALERTS 序列上,但规则 labels 的cluster优先级更高,把 externalLabels 覆盖掉了。这可以从 ALERTS 序列同时存在prometheus、prometheus_replica(externalLabels 加进来的)而 cluster 却是 kafka 值看出来。
四、解决方案
确认根因后,删除 rules/kafka/kafka-rules.yaml 中全部 18 处 cluster: "{{ $labels.kafka_cluster }}" 行。
cd k8s部署yaml/prometheus/kube-prometheus-stack/clusterA-prod-xc-kube-prometheus-stack
# 删除 rules/kafka/kafka-rules.yaml 中 18 处 cluster: "{{ $labels.kafka_cluster }}"
选择删除而不是改成固定值,原因:删掉后 ALERTS 序列的 cluster 自动回落到 externalLabels 的 clusterA-prod-xc,cluster 变量只剩两个真实集群值,最干净;要是改成 clusterA-kafka-cluster 固定值,变量里还是会残留一个 kafka 集群维度值。
五、验证
5.1 文件层面
# 确认无残留模板
grep -n 'cluster:.*kafka_cluster\|cluster:.*{{\$' rules/kafka/kafka-rules.yaml
# 无输出
# YAML 结构校验(18 条告警规则均无 cluster 标签)
python3 -c "import yaml; d=yaml.safe_load(open('rules/kafka/kafka-rules.yaml')); print(len(d['spec']['groups']))"
文件内 cluster 关键字仅剩 expr 表达式中的 kafka_cluster(聚合运算用的原始指标标签),与告警 labels 无关。
5.2 机制层面
- annotations(summary/description)里引用的标签是
$labels.systemName、$labels.instance、$labels.topic、$labels.persistentvolumeclaim、$value等,无一处引用$labels.cluster,删除不影响告警文案渲染。 - Alertmanager 配置(values.yaml 396-589 行)的路由 matchers、group_by、inhibit_rules 分别依赖
alertname/app/severity/service/instance/alertCategory,无一处依赖 cluster,删除不影响告警分发与抑制。
5.3 生产环境验证
- 已
kubectl apply -f该 PrometheusRule(或 helm upgrade)使其生效 - 生效后 VM 里旧的 ALERTS 序列随时间过期消失
- 最终确认:Grafana cluster 变量刷新后只剩
clusterA-prod-xc/clusterB-prod-xc,clusterA-kafka-cluster和{{ $labels.kafka_cluster }}两个垃圾值都没了,闭环。
结论(2026-08-11 生产验证):cluster 变量回归两个真实集群值,根因链条与修复方案完全闭环。
六、注意事项
- 告警规则的
labels不只是告警通知标签,会落进 TSDB 的 ALERTS 序列,从而影响label_values类全序列扫描查询。 - Grafana 变量”Preview 有值但数据源里找不到”时,先确认 Grafana 数据源指向。跨集群 remoteWrite 汇总场景下,数据源通常是 VictoriaMetrics 而非本地 Prometheus。
- 外部标签(externalLabels)会被规则 labels 覆盖,排查 cluster 类标签时两个来源都要看。
sum by(...)等聚合查询会丢弃未列入 by 的标签;模板引用被丢弃的标签时,结果是空值或字面量,容易因此出错。- PrometheusAlert 微信模板由外部服务(
prometheus-alert-center)渲染,若其模板引用了cluster标签,Kafka 告警推送中该字段会变空,需到 PrometheusAlert 服务端模板确认。