openfalcon源碼分析之Judge

openfalcon源碼分析之Judge

本節內容

  1. Judge功能
  2. 源碼分析
  3. 設計優缺點

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. 源碼分析

處理流程分析

接收數據方

  1. 經過RPC註冊兩個方法,一個是ping,返回一個nil的返回值,另外一個是send,處理transfer發送過來的數據。
  2. 對於transfer發送過來的每一個監控數據,都會生成一個pk(對數據的endpoint,metric,tags進行字符串拼接,以後再用md5進行hash,生成一個hash值)。經過pk的前兩位hash值,去HistoryBigMap中找到對應的值,調用PushFrontAndMaintain。(HistoryBigMap的結構會在後面進行講解)
  3. 調用PushFrontAndMaintain會去JudgeItemMap中找到pk對應的值(鏈表)
    • 若該pk能找到值,則調用該鏈表的PushFrontAndMaintain方法,將新到來的監控數據和鏈表最大長度傳遞進去。鏈表的PushFrontAndMaintain方法將新監控數據插入到鏈表的頭部,若是超過了最大長度,則把最老的數據刪除。再調用Judge方法對新監控數據和歷史數據進行判斷。函數

    • 若沒找到值,則會新建立一個鏈表,把新監控數據放入鏈表中。再調用Judge方法對新監控數據和歷史數據進行判斷。
  4. 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兩個字典。源碼分析

幾個數據結構分析

  1. HistoryBigMap
    • HistoryBigMap是個大字典,key是pk的hash值的前兩位,一共有16*16=256個鍵,value是NewJudgeItemMap,也是一個字典,該字典的key是pk,value對應歷史數據組成的鏈表,鏈表最大長度可在配置文件中的remain配置,默認是11,也就是默認對每一個數據,保留11個歷史數據節點。
  2. StrategyMap
    • StrategyMap是個字典,key是hostname和Metric拼接的字符串,value是一個array,由於同一個hostname和Metric可能對應多個Strategy(可能tags不一樣,固然可能沒有tags時,父子模板中都有該Strategy)
  3. ExpressionMap
    • ExpressionMap是個字典,key是metric和tags拼接的字符串,value是一個array,metric和tags沒法惟一肯定expression。
  4. LastEvents
    • LastEvents是個字典,key是event.Id,該id是由strategy.id和pk的hash值拼接產生的,能夠惟一肯定一個數據,因此value就是event事件自己。

3. 設計優缺點

優勢:設計

  1. 支持告警間隔以及最大告警次數,太多的告警並無什麼幫助,何況會將真正有用的告警淹沒在無心義的告警中。
  2. 支持Expression,zabbix是將告警和主機綁定起來,某些並不和某個主機關聯的告警沒法作,有了Expression以後就能夠關聯那一類告警了。

缺點:code

  1. 只支持按照次數告警,若是支持按照時間告警就行了,好比某臺機器連續五分鐘cpu負載太高告警。
相關文章
相關標籤/搜索