告警平臺2.0——仿出強大
在《告警平臺1.0》中,我們實現(xiàn)了告警平臺,可以實現(xiàn)納管通過AlertManager推送的告警信息,然后進行靈活的告警通知發(fā)送。
在這個基礎(chǔ)上,我們可以實現(xiàn)對告警進行認領(lǐng)、屏蔽、關(guān)閉等操作,也能在移動端進行操作。
但是,這個方案現(xiàn)在只能被動的接受告警,對于告警規(guī)則還是需要到Prometheus中去配置,當告警規(guī)則較多的情況下,配置分類比較麻煩,所以在想:能不能在現(xiàn)有平臺上增加規(guī)則配置監(jiān)控功能?
所以,我又到老朋友《快貓Flashcat》上進行學習,它們除了有故障管理,也有告警管理,可以實現(xiàn)監(jiān)控告警一體化。
而且,它支持的數(shù)據(jù)源還比較多,如下:
當然,我不需要實現(xiàn)這么多,只要把常用的Prometheus和Elasticsearch實現(xiàn)即可。
邏輯梳理
相對來說,監(jiān)控規(guī)則的實現(xiàn)邏輯還是比較清晰,如下:
本質(zhì)上就是后臺系統(tǒng)周期性的在數(shù)據(jù)庫(Prometheus、Elasticsearch)中通過規(guī)則進行查詢,當異常條件滿足后,就生成對應(yīng)的告警事件,然后將告警事件分發(fā)到協(xié)作空間
。
另外,為了提升告警事件的管理效率,避免頻繁查詢、更新數(shù)據(jù)庫,當產(chǎn)生告警事件后,會將其存入Redis,告警事件更新會同步更新Redis中的數(shù)據(jù)。同時,后端會有一個常駐的攜程,獲取Redis中的告警事件,評估是否需要發(fā)送到協(xié)作空間。
實現(xiàn)效果
為了便于規(guī)則的管理,我們建立了分組,這里的分組沒有和協(xié)作空間建立必然的聯(lián)系,只是為了便于管理告警規(guī)則。
告警規(guī)則就會按組進行分類展示
創(chuàng)建規(guī)則,目前支持創(chuàng)建Prometheus和Elasticsearch規(guī)則。
創(chuàng)建Prometheus規(guī)則。
我們可以:
- 為規(guī)則添加附加標簽,比如為了按標簽進行告警發(fā)送的時候添加biz=a的標簽。
- 定義具體的PromQL。
- 指定告警評估表達式,目前支持嚴重、警告、通知三個表達式。
- 可以配置告警持續(xù)時間,只有當告警事件超過持續(xù)時間,才會產(chǎn)生真正的告警事件。
- 可以配置通知詳情,便于人員閱讀。
- 可以配置通知渠道,將事件推送到某個協(xié)作空間。
當告警產(chǎn)生后就會發(fā)送到對應(yīng)的渠道,比如發(fā)送到企微的消息如下:
創(chuàng)建Elasticsearch規(guī)則。
主要配置的地方:
- 指定數(shù)據(jù)源:需要配置告警的數(shù)據(jù)源地址
- 指定索引:針對哪個索引做規(guī)則
- 指定篩選字段:通過這些字段進行過濾日志
- 指定標注字段:在發(fā)送告警通知的時候會將該部分發(fā)送到群里,便于運維開發(fā)提取關(guān)鍵信息
其中,添加標注是為了在展示需要的告警信息,比如:
另外,分組評估
用戶將告警信息進行分組發(fā)送,觸發(fā)條件
用于判斷是不是發(fā)送告警通知。
當告警事件產(chǎn)生,就會發(fā)送一條告警通知,如下:
日志監(jiān)控的告警邏輯也比較簡單,如下:
代碼實現(xiàn)
對于Prometheus監(jiān)控規(guī)則,定時從Prometheus時序數(shù)據(jù)庫中查詢值,然后和配置的策略進行比較,如果滿足要求則產(chǎn)生告警事件。
// 從時序數(shù)據(jù)庫中查詢數(shù)據(jù)
resQuery, err = cli.(global.PrometheusProvider).Query(rule.PrometheusConfig.PromQL)
// 然后將值進行比較
for _, v: = range resQuery {
for _, ruleExpr: = range rule.PrometheusConfig.Rules {
// 去除空格
cleanedExpr: = strings.ReplaceAll(ruleExpr.Expr, " ", "")
re: = regexp.MustCompile(`([^\d]+)(\d+)`)
matches: = re.FindStringSubmatch(cleanedExpr)
if len(matches) < 2 {
continue
}
t,
_: = strconv.ParseFloat(matches[2], 64)
option: = alarmCenter.EvalCondition {
Operator: matches[1],
QueryValue: v.Value,
ExpectedValue: t,
}
// 進行比較,當滿足條件后生成事件
if ok := alarmCenter.EvalCondition(option);ok{
event := alarmCenter.BuildAlertEvent(rule)
alarmCenter.SaveAlertEvent(event)
}
}
}
對于Elasticsearch監(jiān)控規(guī)則,定時從Elasticsearch數(shù)據(jù)庫中查詢滿足日志條數(shù),當滿足告警條件后生成告警事件。
// 從ES中查詢值
curAt: = time.Now()
startsAt: = utils.ParserDuration(curAt, int(rule.ElasticsearchConfig.Scope), "m")
queryOptions: = provider.LogQueryOptions {
ElasticSearch: provider.Elasticsearch {
Index: rule.ElasticsearchConfig.Index,
QueryFilter: rule.ElasticsearchConfig.Filter,
Annotations: rule.ElasticsearchConfig.Annotations,
GroupEval: rule.ElasticsearchConfig.GroupEval,
},
StartAt: utils.FormatTimeToUTC(startsAt.Unix()),
EndAt: utils.FormatTimeToUTC(curAt.Unix()),
}
queryRes, count, err = cli.(global.ElasticsearchProvider).Query(queryOptions)
option := alarmCenter.EvalCondition {
Operator: rule.ElasticsearchConfig.TriggerCondition.Operator,
QueryValue: float64(count),
ExpectedValue: rule.ElasticsearchConfig.TriggerCondition.ExpectedValue,
}
// 進行比較,當滿足條件后生成事件
if ok := alarmCenter.EvalCondition(option);ok{
event := alarmCenter.BuildAlertEvent(rule)
alarmCenter.SaveAlertEvent(event)
}
條件評估的代碼如下:
func EvalCondition(ec alarmCenter.EvalCondition) bool {
// 使用 map 存儲操作符對應(yīng)的比較函數(shù)
operatorMap := map[string]func(float64, float64) bool{
">": func(a, b float64) bool { return a > b },
">=": func(a, b float64) bool { return a >= b },
"<": func(a, b float64) bool { return a < b },
"<=": func(a, b float64) bool { return a <= b },
"==": func(a, b float64) bool { return a == b },
"=": func(a, b float64) bool { return a == b },
"!=": func(a, b float64) bool { return a != b },
}
// 查找并執(zhí)行對應(yīng)的比較函數(shù)
if compareFunc, exists := operatorMap[ec.Operator]; exists {
return compareFunc(ec.QueryValue, ec.ExpectedValue)
}
global.GVA_LOG.Error(fmt.Sprintf("無效的評估條件,%s:%s:%f", ec.Type, ec.Operator, ec.ExpectedValue))
return false
}
告警通知的邏輯還是不變,當監(jiān)聽到告警事件后,進行對應(yīng)的告警通知。