zoukankan      html  css  js  c++  java
  • openfalcon源码分析之Judge

    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负载过高告警。
  • 相关阅读:
    iOS 微信支付SDK与微信友盟分享两者同时集成时,出现的问题与解决之路。
    Object-C语言Block的实现方式
    使用Mac命令别名,提升工作效率
    利用OC对象的消息重定向forwardingTargetForSelector方法构建高扩展性的滤镜功能
    渐变色进度条的两种绘制方案
    设计模式应用场景之Model设计中可以用到的设计模式
    有趣的赫夫曼树
    技术团队管理者的问题视角
    SSH安全登陆原理:密码登陆与公钥登陆
    为什么HashMap继承了AbstractMap还要实现Map?
  • 原文地址:https://www.cnblogs.com/huxianglin/p/7419794.html
Copyright © 2011-2022 走看看