openfalcon源碼分析之Judge
本節內容
- Judge功能
- 源碼分析
- 設計優缺點
1. Judge功能
在open-falcon中,Judge模塊的功能是經過從HBS上同步告警的strategys(告警策略),及Expression,用來在接收transfer上報過來的數據時,對數據進行檢測,每收到一條上報的數據,就去匹配對應的strategy和Expression是否知足條件,判斷是否須要向redis發送告警。golang
告警策略
open-falcon中的策略有兩類,strategys和Expression。strategys與主機進行管線,能夠經過一個主機找到其對應的全部strategys。而Expression則不須要有任何關聯,是對全局範圍內進行的一個過濾和判斷。redis
stratrgys查找策略
從transfer上接收過來的數據帶有endpoint,經過主機能夠找到其對應的主機組(主機和主機組是多對多的關係),經過主機組能夠找到對應的模板組(模板和主機組是多對多的關係),模板之間又可能有繼承關係,經過模板組能夠找到對應的strategy(模板和strategy是一對多的關係)一個模板就是一組strategy的集合。這樣就能夠經過上報過來的數據的endpoint找到其對應的全部的strategys了。express
expression查找策略
expression不和主機關聯,其針對的是全局的配置,主要對應一些須要特殊定製的告警檢查。數據結構
2. 源碼分析
處理流程分析
接收數據方
- 經過RPC註冊兩個方法,一個是ping,返回一個nil的返回值,另外一個是send,處理transfer發送過來的數據。
- 對於transfer發送過來的每一個監控數據,都會生成一個pk(對數據的endpoint,metric,tags進行字符串拼接,以後再用md5進行hash,生成一個hash值)。經過pk的前兩位hash值,去HistoryBigMap中找到對應的值,調用PushFrontAndMaintain。(HistoryBigMap的結構會在後面進行講解)
- 調用PushFrontAndMaintain會去JudgeItemMap中找到pk對應的值(鏈表)
- Judge方法會調用CheckStrategy方法以及CheckExpression方法對新監控數據和歷史數據進行處理。
- CheckStrategy方法先將監控數據中的endpoint和metric進行字符串拼接成key,經過key去strategys中尋找對應的strategys列表。對於一個監控數據若是找到了多個strategy,則會對每一個strategy的tags進行匹配,若和監控數據不符合則被過濾掉。剩下的每一個strategys將會調用judgeItemWithStrategy方法,該方法先將strategy的表達式進行拼接找到對應的函數,而後將歷史數據傳遞到Compute中進行邏輯判斷,若是判斷匹配則返回的值isTriggered爲true,不然返回false.在judgeItemWithStrategy中會建立event事件,調用sendEventIfNeed方法判斷該event是否應該發送出去。
- sendEventIfNeed方法會去檢查LastEvents中該event是否已經存在,並按照必定規則判斷是否須要調用sendEvent將event發送到redis中。源碼以下.
- CheckExpression方法先將監控數據中的endpoint、metric、tags進行字符串拼接成key,再用該key在ExpressionMap字典中檢查是否有對應的expressions,若是找到則調用filterRelatedExpressions進行處理
- filterRelatedExpressions檢查全部對應的expressions,篩選掉tags不匹配的expressions,剩下的就是全部符合條件的expressions,針對全部符合條件的expressions,調用judgeItemWithExpression構建告警event,後面的處理步驟和strategys一致。
// sendEventIfNeed方法中判斷event是否該發告警的邏輯
if isTriggered {
event.Status = "PROBLEM"
if !exists || lastEvent.Status[0] == 'O' {
// 本次觸發了閾值,以前又沒報過警,得產生一個報警Event
event.CurrentStep = 1
// 可是有些用戶把最大報警次數配置成了0,至關於屏蔽了,要檢查一下
if maxStep == 0 {
return
}
sendEvent(event)
return
}
// 邏輯走到這裏,說明以前Event是PROBLEM狀態
if lastEvent.CurrentStep >= maxStep {
// 報警次數已經足夠多,到達了最多報警次數了,再也不報警
return
}
if historyData[len(historyData)-1].Timestamp <= lastEvent.EventTime {
// 產生過報警的點,就不能再使用來判斷了,不然容易出現一分鐘報一次的狀況
// 只須要拿最後一個historyData來作判斷便可,由於它的時間最老
return
}
if now-lastEvent.EventTime < g.Config().Alarm.MinInterval {
// 報警不能太頻繁,兩次報警之間至少要間隔MinInterval秒,不然就不能報警
return
}
event.CurrentStep = lastEvent.CurrentStep + 1
sendEvent(event)
} else {
// 若是LastEvent是Problem,報OK,不然啥都不作
if exists && lastEvent.Status[0] == 'P' {
event.Status = "OK"
event.CurrentStep = 1
sendEvent(event)
}
}
同步strategy和expressions方
main函數中起了go-routine 專門用來從hbs同步strategy和expressions,同步完以後從新組裝成StrategyMap和ExpressionMap兩個字典。源碼分析
幾個數據結構分析
- HistoryBigMap
- HistoryBigMap是個大字典,key是pk的hash值的前兩位,一共有16*16=256個鍵,value是NewJudgeItemMap,也是一個字典,該字典的key是pk,value對應歷史數據組成的鏈表,鏈表最大長度可在配置文件中的remain配置,默認是11,也就是默認對每一個數據,保留11個歷史數據節點。
- StrategyMap
- StrategyMap是個字典,key是hostname和Metric拼接的字符串,value是一個array,由於同一個hostname和Metric可能對應多個Strategy(可能tags不一樣,固然可能沒有tags時,父子模板中都有該Strategy)
- ExpressionMap
- ExpressionMap是個字典,key是metric和tags拼接的字符串,value是一個array,metric和tags沒法惟一肯定expression。
- LastEvents
- LastEvents是個字典,key是event.Id,該id是由strategy.id和pk的hash值拼接產生的,能夠惟一肯定一個數據,因此value就是event事件自己。
3. 設計優缺點
優勢:設計
- 支持告警間隔以及最大告警次數,太多的告警並無什麼幫助,何況會將真正有用的告警淹沒在無心義的告警中。
- 支持Expression,zabbix是將告警和主機綁定起來,某些並不和某個主機關聯的告警沒法作,有了Expression以後就能夠關聯那一類告警了。
缺點:code
- 只支持按照次數告警,若是支持按照時間告警就行了,好比某臺機器連續五分鐘cpu負載太高告警。