Alertmanager 处理由 Prometheus 服务器等客户端应用程序发送的告警。负责对它们进行分组、静默、抑制、去重并路由到正确的接收方,例如Email、Wechat、Webhook。
Prometheus告警处理逻辑的问题
在prometheus告警体系中,在告警策略正常运行时,检测到有新的符合告警规则的信息,就产生告警发送给alertmanager,如果恢复了,也会产生恢复的信息发送给alertmangaer,这是理想的情况。 如果在告警过程中有发生告警规则的更新,比如发现告警阈值太低,调整了阈值,那么在prometheus的更新过程中,会丢弃老的评估信息,直接使用新的评估规则再次运行评估,评估过程中,如果不会再产生告警,也不会产生恢复信息。 那就会产生一个问题,以前发送给Alertmanager的旧规则生成的告警,不会收到恢复了。 总结下就是:
-
每个评估周期持续发送告警给Alertmanger。
如果有规则更新,直接新启goroutine执行新的评估,直接放弃老的规则和goroutine。
Alertmanager的修复逻辑
Prometheus评估后发送给Alertmanger的firing告警是没有结束时间的。
[ { "labels": { "alert_class": "metric", "alert_rule_id": "940", "alert_severity": "1", "alert_strategy": "cwhistle_demo_00", "alert_strategy_id": "100", "alertname": "入流量异常告警", "city": "chongqing2", "tcs_instance": "10.27.38.145", "tcs_product": "clb", "tcs_type": "clb_tgw_inner_outer" }, "annotations": { "query": "barad_tbr{tcs_type=~\"clb_tgw_inner_outer\",tcs_product=~\"clb\",clb_tgw_inner_outer=~\"10.27.38.145|10.27.38.146\"} < 5", "value": "0.00" }, "state": "firing", "activeAt": "2021-01-25T08:31:34.941070644Z", "value": "0e+00" } ]
在Alertmanger中,告警的触发和恢复判断是基于时间范围实现的,Alertmanager中Alert定义如下,自带时间范围。
// Alert is a generic representation of an alert in the Prometheus eco-system. type Alert struct { // Label value pairs for purpose of aggregation, matching, and disposition // dispatching. This must minimally include an "alertname" label. Labels LabelSet `json:"labels"` // Extra key/value information which does not define alert identity. Annotations LabelSet `json:"annotations"` // The known time range for this alert. Both ends are optional. StartsAt time.Time `json:"startsAt,omitempty"` EndsAt time.Time `json:"endsAt,omitempty"` GeneratorURL string `json:"generatorURL"` }
当 Alert.EndsAt < time.Now() 时判定为恢复。
// 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) }
在Api的接收过程中,会确保每个Alert的StartsAt和EndsAt有值。
func (api *API) postAlertsHandler(params alert_ops.PostAlertsParams) middleware.Responder { logger := api.requestLogger(params.HTTPRequest) alerts := OpenAPIAlertsToAlerts(params.Alerts) now := time.Now() api.mtx.RLock() resolveTimeout := time.Duration(api.alertmanagerConfig.Global.ResolveTimeout) api.mtx.RUnlock() for _, alert := range alerts { alert.UpdatedAt = now // Ensure StartsAt is set. if alert.StartsAt.IsZero() { if alert.EndsAt.IsZero() { alert.StartsAt = now } else { alert.StartsAt = alert.EndsAt } } // If no end time is defined, set a timeout after which an alert // is marked resolved if it is not updated. if alert.EndsAt.IsZero() { alert.Timeout = true alert.EndsAt = now.Add(resolveTimeout) } if alert.EndsAt.After(time.Now()) { api.m.Firing().Inc() } else { api.m.Resolved().Inc() } } .....
在上述代码中可以看到,alert.EndsAt= time.Now() + 全局配置的ResolveTimeout(默认5分钟),也就是每个Alert默认给5分钟的过期时间,过期就恢复。
事件告警自定义过期时间
默认的5分钟对于prometheus metric告警是足够的,但如果想使用基于loki的日志告警(通常为了控制资源消耗,不会设置很大的评估范围),有时候偶发一个告警,然后很快就恢复了;或者想基于Event类型的事件告警,因为触发频率低,且不会持续发送,5分钟就比较容易误解。 那么在这里我们就可以基于Label着色和修改过期时间的方法自定义事件告警过期恢复时间。 实现如下: 这样就可以实现事件告警的自定义恢复时间,同时可以利用Alertmanager已有的其他功能。
转载请注明:IT运维空间 » 运维技术 » 深入理解Alertmanager:源码解读如何自定义Alert的恢复时间
发表评论