Prometheus AlertManager 报警配置与实战详解
总的流程图:
alerts:
先快速梳理 AlertManager 中告警的基础概念与状态模型。每条告警对应一个具体事件,包含名称、触发时间、当前状态以及用户自定义的详细说明。其基本数据结构如下:
[{"startsAt": "2019-06-03T03:32:20.859Z","endsAt": "2019-06-03T03:32:20.859Z","annotations":{"additionalProp1": "string","additionalProp2": "string","additionalProp3": "string"},"labels":{"additionalProp1": "string","additionalProp2": "string","additionalProp3": "string"},"generatorURL": "string"}]
告警的唯一标识如何生成?系统将 labels 字段下的所有键值对组合后计算出一个指纹(fingerprint),因此 labels 集合本身即可视作唯一标识。所有告警的合并、状态更新均依赖此指纹进行精确定位。相关代码实现如下:
// Fingerprint returns a unique hash for the alert. It is equivalent to
// the fingerprint of the alert's label set.
func (a *Alert) Fingerprint() Fingerprint {
return a.Labels.Fingerprint()
}
// labelSetToFingerprint works exactly as LabelsToSignature but takes a LabelSet as
// parameter (rather than a label map) and returns a Fingerprint.
func labelSetToFingerprint(ls LabelSet) Fingerprint {
if len(ls) == 0 {
return Fingerprint(emptyLabelSignature)
}
labelNames := make(LabelNames, 0, len(ls))
for labelName := range ls {
labelNames = append(labelNames, labelName)
}
sort.Sort(labelNames)
sum := hashNew()
for _, labelName := range labelNames {
sum = hashAdd(sum, string(labelName))
sum = hashAddByte(sum, SeparatorByte)
sum = hashAdd(sum, string(ls[labelName]))
sum = hashAddByte(sum, SeparatorByte)
}
return Fingerprint(sum)
}
告警状态仅包含两种:firing(触发中)和 resolved(已恢复)。该值由 Manager 根据收到的告警结构自动判定。什么情况下视为 firing?当 endsAt 字段为空,或当前时间小于等于 endsAt 时,告警处于触发状态。什么情况下视为 resolved?当 endsAt 非空且大于当前时间。判断逻辑一目了然:
// Resolved returns true iff the activity interval ended in the past.
func (a *Alert) Resolved() bool {
return a.ResolvedAt(time.Now())
}
// ResolvedAt returns true off the activity interval ended before
// the given timestamp.
func (a *Alert) ResolvedAt(ts time.Time) bool {
if a.EndsAt.IsZero() {
return false
}
return !a.EndsAt.After(ts)
}
router
路由可以抽象为一棵树,通过树形结构灵活控制告警的流转路径。根节点即为 router,其所有属性可被子节点继承,因此根节点属性相当于全局默认值。子节点 routers 支持零个或多个,每个子节点可独立配置属性以覆盖父节点设定。
每个 router 包含以下几类控制参数:
- 匹配规则:
match和match_re,前者执行等值匹配,后者支持正则表达式,用于决定告警是否路由至当前节点。 - 流程控制:
continue表示告警是否继续向下路由;若为 false,则告警终止于此节点,不再向下传递。 - 分组规则:group 相关参数,用于告警聚合。
- 接收端:
receiver指定处理方式,例如发送邮件、调用 Webhook 等。
group
分组操作的核心价值在于将同类告警归并至一条通知中。典型场景:当某个关键服务或组件故障时,可能瞬间触发成百上千条相似告警。通过分组聚合,通知数量大幅减少,保持信息清晰有效。分组涉及三个关键参数:
- group by:指定按哪个 label 进行分组,多个 label 用逗号分隔。
- group_wait:从首个新分组创建开始,到实际发送告警通知之间的等待时间。系统会在该窗口内将同一分组的新告警合并后统一发送。
- group_interval:同一分组成功发送后,后续再出现同组告警时,需等待此间隔才能发起下一轮通知。
storage
AlertManager 不提供历史存储能力,仅保存告警的当前快照。存储分为两部分:
(1)告警状态快照:仅保留尚未恢复的告警,存储周期可配置,默认值为 120 小时。底层采用 map 结构,key 的格式为 GroupKey:r.GroupName,/r.Integration,/r.Idx,value 为 MeshEntry。具体定义如下:
type MeshEntry struct {
Entry *Entry `protobuf:"bytes,1,opt,name=entry,proto3" json:"entry,omitempty"`
ExpiresAt time.Time `protobuf:"bytes,2,opt,name=expires_at,json=expiresAt,proto3,stdtime" json:"expires_at"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
type Entry struct {
GroupKey []byte `protobuf:"bytes,1,opt,name=group_key,json=groupKey,proto3" json:"group_key,omitempty"`
Receiver *Receiver `protobuf:"bytes,2,opt,name=receiver,proto3" json:"receiver,omitempty"`
GroupHash []byte `protobuf:"bytes,3,opt,name=group_hash,json=groupHash,proto3" json:"group_hash,omitempty"`
Resolved bool `protobuf:"varint,4,opt,name=resolved,proto3" json:"resolved,omitempty"`
Timestamp time.Time `protobuf:"bytes,5,opt,name=timestamp,proto3,stdtime" json:"timestamp"`
FiringAlerts []uint64 `protobuf:"varint,6,rep,packed,name=firing_alerts,json=firingAlerts,proto3" json:"firing_alerts,omitempty"`
ResolvedAlerts []uint64 `protobuf:"varint,7,rep,packed,name=resolved_alerts,json=resolvedAlerts,proto3" json:"resolved_alerts,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
(2)告警静音状态:静音规则的存储周期由规则自身配置决定,此处不展开细节。
