Alertmanager Label Lifecycle#
Alertmanager 的 group_by、route.matchers、inhibit_rules.equal 都只看最终 alert labels。要判断 group_by 是否能正确聚合,必须知道从 scrape metrics 到 Alertmanager 中间有哪些地方会新增、删除、改名或覆盖 label。
Links#
https://prometheus.io/docs/prometheus/latest/configuration/configuration/
https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/
https://prometheus.io/docs/prometheus/latest/querying/operators/
https://prometheus.io/docs/alerting/latest/configuration/
https://docs.victoriametrics.com/victoriametrics/vmagent/
https://docs.victoriametrics.com/victoriametrics/vmalert/1. Label Sources#
exporter / application:
metric 自带 labels
example: method / status / instance / dimension_TableName
service discovery:
__address__ / __scheme__ / __metrics_path__ / __meta_* internal labels
这些 label 主要给 relabel_configs 使用
scrape config:
job_name 生成 job label
static_configs.labels 可以给 target 添加 labels
relabel_configs 可以 keep / drop / replace / labelmap
scrape result:
target labels 会附加到每条 scraped sample
默认会有 job 和 instance
metric_relabel_configs:
scrape 后、写入存储前处理每条 sample
可以删除 sample、删除 label、改 label value
remote write / vmagent:
可以在发送到 VictoriaMetrics 前继续 relabel
可以配置全局额外 label
PromQL / MetricsQL expression:
selector 保留原 series labels
aggregation by (...) 只保留 by 里列出的 labels
without (...) 删除指定 labels,保留其他 labels
binary operation 可能根据 on / ignoring 改变保留的 label set
vmalert / Prometheus alerting rule:
alertname 自动变成 alert label
expr 结果 labels 会进入 alert
rule labels 会添加到 alert,并覆盖同名 label
group labels / external labels 如果配置了,也可能添加到 alert
Alertmanager:
接收最终 labels
route / group_by / inhibition / silence 都基于这些 labels
annotations / startsAt / endsAt / generatorURL 不是 labels2. Order#
1. exporter exposes metric labels
2. service discovery creates __meta_* internal labels
3. scrape relabel_configs modifies target labels before scrape
4. scrape attaches target labels to samples
5. metric_relabel_configs modifies sample labels before ingestion
6. vmagent remote write relabel / extra labels modifies outgoing samples
7. VictoriaMetrics stores final metric labels
8. vmalert query expression returns series labels
9. aggregation keeps or drops labels
10. alerting rule adds alertname and rule labels
11. vmalert external labels may be added
12. Alertmanager receives final alert labels最容易丢 label 的地方:
metric_relabel_configs:
labeldrop / labelkeep / replace 写错
aggregation:
sum by (...) 没有保留后续 group_by 需要的 label
rule labels:
手动配置了同名 label,覆盖了 expr 结果里的 label
external labels:
使用了和业务 label 同名的 key,造成理解混乱3. Where To Add Labels#
核心原则:
越靠近数据源:
越适合加目标身份 label
越靠近告警规则:
越适合加告警语义 label按阶段拆开看:
| Stage | Good Labels | Avoid Labels | Why |
|---|---|---|---|
| vmagent scrape / relabel | environment, region, cluster, account_id, instance_name, role, team, service |
component=filesystem, severity, alert_type |
这里描述的是 target / metric 从哪里来、属于谁、在哪个环境 |
| recording rule | 保留 environment, service, instance_name, mountpoint, dimension_LoadBalancer, dimension_TargetGroup, dimension_QueueName |
不需要的高基数 label,比如 pod_uid, container_id, request_id |
aggregation 会决定后续 alert 还能看到哪些 label |
| alert rule labels | severity, component, team, alertgroup, runbook_class, service |
动态资源值,比如固定写死 dimension_TargetGroup |
这里描述的是这条告警的性质、路由、归属和处理方式 |
Node exporter example:
vmagent scrape labels:
environment="uat"
service="ec2"
instance_name="ping-uat-devops"
alert rule labels:
severity="warning"
component="filesystem"
final alert labels:
alertname="AwsEc2DiskUsedHigh"
environment="uat"
service="ec2"
instance_name="ping-uat-devops"
component="filesystem"
severity="warning"不要在 node exporter scrape 阶段统一加 component="filesystem"。同一个 node exporter target 会产生 CPU、memory、filesystem、network 等多类 metric;如果太早加 component=filesystem,CPU / memory 告警也可能继承错误的 component,并命中错误的 Alertmanager route。
4. vmagent Scrape Sample#
Scrape config:
global:
external_labels:
monitor: vmagent-uat
scrape_configs:
- job_name: yace
scrape_interval: 60s
static_configs:
- targets:
- 127.0.0.1:5000
labels:
env: uat
cluster: ping-uat
exporter: yace
relabel_configs:
- target_label: region
replacement: ap-east-1
metric_relabel_configs:
- regex: dimension_AvailabilityZone
action: labeldrop
# 示例目的:删除 AZ label,真实配置要按实际需要决定Exporter 原始 metric:
aws_applicationelb_target_response_time_p95{
dimension_LoadBalancer="ping-uat-alb",
dimension_TargetGroup="sub2api-targets",
dimension_AvailabilityZone=""
} 1.25Scrape target labels:
job:
yace
instance:
127.0.0.1:5000
env / cluster / exporter:
来自 static_configs.labels
region:
来自 relabel_configsAfter scrape and metric relabel:
aws_applicationelb_target_response_time_p95{
job="yace",
instance="127.0.0.1:5000",
env="uat",
cluster="ping-uat",
exporter="yace",
region="ap-east-1",
dimension_LoadBalancer="ping-uat-alb",
dimension_TargetGroup="sub2api-targets"
} 1.25Notes:
__meta_*:
只在 relabel 阶段使用,默认不会进入最终 metric
dimension_AvailabilityZone:
这里被 metric_relabel_configs 删除
job / instance:
常见默认 target labels5. Label Conflict#
如果 scraped metric 自己带了 job / instance / env 这类 label,可能和 scrape target labels 冲突。
默认行为通常应该理解为:
target label:
由 scrape config / service discovery / relabel_configs 产生
scraped label:
exporter 暴露出来的原始 label
conflict:
默认 target label 优先
scraped 里的冲突 label 会被重命名成 exported_<label>Example:
exporter sample:
http_requests_total{job="app-self", env="inside-app"} 100
scrape target:
job="order-api"
env="prod"
stored sample:
http_requests_total{
job="order-api",
env="prod",
exported_job="app-self",
exported_env="inside-app"
} 100如果设置 honor_labels: true,冲突时会保留 exporter 自己的 label。生产里要谨慎使用,因为它会让 scrape config 中预期的 job / env 被 exporter 覆盖。
6. vmalert Rule Sample#
vmalert 查询 VictoriaMetrics 里的 series。表达式返回哪些 labels,取决于 PromQL/MetricsQL。
groups:
- name: alb-p1.rules
interval: 1m
labels:
team: platform
rules:
- alert: AlbTargetResponseTimeHigh
expr: |
avg by (
env,
cluster,
region,
dimension_LoadBalancer,
dimension_TargetGroup
) (
aws_applicationelb_target_response_time_p95{
env="uat",
dimension_TargetGroup!="",
dimension_LoadBalancer!="ping-uat-alb/canary"
}
) > 1
for: 5m
labels:
severity: P1
service: alb
component: targetgroup
load_balancer: ping-uat-alb
annotations:
summary: "ALB target group p95 latency is high"
description: "Target group {{ $labels.dimension_TargetGroup }} on {{ $labels.dimension_LoadBalancer }} has p95 latency > 1s."Expression output labels:
{env="uat", cluster="ping-uat", region="ap-east-1", dimension_LoadBalancer="ping-uat-alb", dimension_TargetGroup="sub2api-targets"} 1.25Why:
avg by (...):
只保留 by 中列出的 labels
job / instance / exporter 被聚合掉
dimension_TargetGroup:
被保留,因为 by (...) 里写了它
dimension_AvailabilityZone:
之前已经被 metric_relabel_configs 删除,后面无法恢复Final alert labels sent to Alertmanager:
{
alertname="AlbTargetResponseTimeHigh",
env="uat",
cluster="ping-uat",
region="ap-east-1",
dimension_LoadBalancer="ping-uat-alb",
dimension_TargetGroup="sub2api-targets",
team="platform",
severity="P1",
service="alb",
component="targetgroup",
load_balancer="ping-uat-alb"
}Annotations are not labels:
summary:
ALB target group p95 latency is high
description:
Target group sub2api-targets on ping-uat-alb has p95 latency > 1s.Alertmanager group_by 不能使用 summary / description,只能使用 labels 里的 key。
7. Add Routing Labels In Rule#
YACE 采集的 AWS metric 通常只带 AWS dimension,不会自动生成你想用于 Alertmanager route 的业务分类 label。
Raw metric:
aws_applicationelb_request_count_sum{
dimension_LoadBalancer="ping-uat-docmost-alb",
dimension_TargetGroup="ping-uat-docmost-tg",
environment="uat",
job="yace"
}如果 Alertmanager route 需要按 service="alb"、component="targetgroup" 匹配,就在 alert rule 的 labels 里补:
- alert: AwsAlbTargetGroupRequestCountLow
expr: |
sum by (environment, dimension_LoadBalancer, dimension_TargetGroup) (
rate(aws_applicationelb_request_count_sum{dimension_TargetGroup!=""}[5m])
) < 1
for: 5m
labels:
severity: warning
service: alb
component: targetgroup结果:
dimension_LoadBalancer / dimension_TargetGroup:
来自 expr 结果,是动态资源 label
service / component / severity:
来自 rule labels,是静态分类 label不要把动态资源值写死在 rule labels 里,例如不要固定写 dimension_TargetGroup: ping-uat-docmost-tg。这会让所有 alert 都变成同一个 target group。
8. group_by Design#
Alertmanager example:
route:
receiver: lark-monitoring
group_by:
- alertname
- env
- service
- component
- dimension_LoadBalancer
- dimension_TargetGroup
group_wait: 30s
group_interval: 5m
repeat_interval: 4h这个 group_by 能正常工作,因为最终 alert labels 中确实存在:
alertname
env
service
component
dimension_LoadBalancer
dimension_TargetGroup如果 rule 写成:
avg by (env, cluster, region, dimension_LoadBalancer) (...)最终 alert labels 里就没有 dimension_TargetGroup。这时 Alertmanager 不能按 TargetGroup 分组,同一个 ALB 下多个 target group 的告警可能被合并到同一个 group。
Rule labels 可以补静态 label:
labels:
severity: P1
service: alb
component: targetgroupRule labels 不适合补动态资源 label:
bad:
labels:
dimension_TargetGroup: sub2api-targets
reason:
每条 alert 的 target group 应该来自 expr 结果 label
静态写死会让所有 alert 都变成同一个 target group9. Complete Label Timeline#
exporter:
dimension_LoadBalancer="ping-uat-alb"
dimension_TargetGroup="sub2api-targets"
dimension_AvailabilityZone=""
scrape target:
job="yace"
instance="127.0.0.1:5000"
env="uat"
cluster="ping-uat"
exporter="yace"
relabel_configs:
region="ap-east-1"
metric_relabel_configs:
drop dimension_AvailabilityZone
stored metric:
job="yace"
instance="127.0.0.1:5000"
env="uat"
cluster="ping-uat"
exporter="yace"
region="ap-east-1"
dimension_LoadBalancer="ping-uat-alb"
dimension_TargetGroup="sub2api-targets"
vmalert expr avg by:
keep env / cluster / region / dimension_LoadBalancer / dimension_TargetGroup
drop job / instance / exporter
vmalert group labels:
team="platform"
vmalert rule labels:
severity="P1"
service="alb"
component="targetgroup"
load_balancer="ping-uat-alb"
auto alert label:
alertname="AlbTargetResponseTimeHigh"
Alertmanager receives:
alertname
env
cluster
region
dimension_LoadBalancer
dimension_TargetGroup
team
severity
service
component
load_balancer10. How To Verify#
Check stored metric labels:
aws_applicationelb_target_response_time_p95{env="uat", dimension_TargetGroup!=""}Check vmalert active alerts:
curl -s http://vmalert:8880/api/v1/alerts
curl -s http://vmalert:8880/api/v1/rulesCheck Alertmanager received labels:
curl -s http://alertmanager:9093/api/v2/alertsTest route with the same labels:
amtool config routes test \
--config.file=/etc/alertmanager/alertmanager.yml \
alertname=AlbTargetResponseTimeHigh \
env=uat \
service=alb \
component=targetgroup \
dimension_LoadBalancer=ping-uat-alb \
dimension_TargetGroup=sub2api-targets \
severity=P1 \
team=platformRule of thumb:
If a label is missing in stored metric:
check scrape config / relabel_configs / metric_relabel_configs
If a label is present in stored metric but missing in alert:
check PromQL aggregation by (...) / without (...)
If a label is present in alert but value is unexpected:
check rule labels / group labels / external labels for overwrite
If Alertmanager group_by does not work:
inspect /api/v2/alerts and confirm that every group_by key exists in final labels11. Checklist#
Before choosing group_by:
[ ] inspect raw metric labels in Grafana Explore / VMUI
[ ] confirm scrape target labels: job / instance / env / cluster / region
[ ] review relabel_configs and metric_relabel_configs
[ ] check aggregation keeps resource labels needed by group_by
[ ] avoid high-cardinality labels such as pod_uid / request_id
[ ] keep stable labels: alertname / env / service / component / resource
[ ] verify final Alertmanager labels via /api/v2/alerts
Good group_by examples:
alertname / env / service
alertname / env / service / component
alertname / env / service / dimension_QueueName
alertname / env / service / dimension_TableName / dimension_Operation
Risky group_by examples:
instance
pod
container_id
request_id
dynamically generated rule labels