深入理解Alertmanager:源码解读如何自定义Alert的恢复时间

运维 服务器运维
在prometheus告警体系中,在告警策略正常运行时,检测到有新的符合告警规则的信息,就产生告警发送给alertmanager,如果恢复了,也会产生恢复的信息发送给alertmangaer,这是理想的情况。

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已有的其他功能。

责任编辑:姜华 来源: 今日头条
相关推荐

2017-11-13 08:43:57

确保恢复最新

2016-10-26 20:49:24

ReactJavascript前端

2018-06-15 09:26:13

RTORPO差异

2015-01-22 15:59:07

Android源码日期时间控件SelectTime

2014-12-10 10:37:45

Android自定义布局

2016-12-08 15:36:59

HashMap数据结构hash函数

2010-06-01 15:25:27

JavaCLASSPATH

2020-07-21 08:26:08

SpringSecurity过滤器

2012-11-22 10:11:16

LispLisp教程

2010-04-28 12:33:36

Oracle自定义函数

2024-01-29 15:54:41

Java线程池公平锁

2021-10-15 09:19:17

AndroidSharedPrefe分析源码

2021-09-08 06:51:52

AndroidRetrofit原理

2017-01-10 08:48:21

2020-09-23 10:00:26

Redis数据库命令

2017-08-15 13:05:58

Serverless架构开发运维

2024-02-21 21:14:20

编程语言开发Golang

2019-06-25 10:32:19

UDP编程通信

2013-09-22 14:57:19

AtWood

2023-10-19 11:12:15

Netty代码
点赞
收藏

51CTO技术栈公众号