1. 程式人生 > >openfalcon源碼分析之Judge

openfalcon源碼分析之Judge

個數 長度 cnblogs fig -m mmap 字符串拼接 邏輯 nmap

openfalcon源碼分析之Judge

本節內容

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

1. Judge功能

在open-falcon中,Judge模塊的功能是通過從HBS上同步告警的strategys(告警策略),及Expression,用來在接收transfer上報過來的數據時,對數據進行檢測,每收到一條上報的數據,就去匹配對應的strategy和Expression是否滿足條件,判斷是否需要向redis發送告警。

告警策略

open-falcon中的策略有兩類,strategys和Expression。strategys與主機進行管線,可以通過一個主機找到其對應的所有strategys。而Expression則不需要有任何關聯,是對全局範圍內進行的一個過濾和判斷。

stratrgys查找策略

從transfer上接收過來的數據帶有endpoint,通過主機可以找到其對應的主機組(主機和主機組是多對多的關系),通過主機組可以找到對應的模板組(模板和主機組是多對多的關系),模板之間又可能有繼承關系,通過模板組可以找到對應的strategy(模板和strategy是一對多的關系)一個模板就是一組strategy的集合。這樣就可以通過上報過來的數據的endpoint找到其對應的所有的strategys了。

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之後就可以關聯那一類告警了。

缺點:

  1. 只支持按照次數告警,如果支持按照時間告警就好了,比如某臺機器連續五分鐘cpu負載過高告警。

openfalcon源碼分析之Judge