zoukankan      html  css  js  c++  java
  • 分布式监控系统开发【day38】:报警阈值程序逻辑解析(三)

    一、需求讨论

    1、请问如何解决延迟问题

    1000台机器,每1分钟循环一次但是刚好第一次循环第一秒刚处理完了,结果还没等到第二分钟又出问题,你那必须等到第二次循环,假如我这个服务很重要必须实时知道,
    每次客户端汇报过来的同时,触发trigger检测,就可以实时的实现报警反应

    2、这样有什么问题?

    前提是它给你汇报,如果客户端网络断了,客户端宕机了,就无法汇报了

    3、你要确保客户端存活的检测机制

    拿到每台机器的所有触发器,检测阈值,如果超过阈值,存到redis
    你不用再连redis我给你传(从外部调用 时才用的到,为了避免重复调用 redis连接)

    二、那个表达式触发了报警?

    1、开发目标为红框内内容

    2、触发报警函数功能

    def load_service_data_and_calulating()的功能如下:
    	[ iowait.avg(5) >10 and ,idle < 20 or ,mem_usage > 80% and, disk > 90% ]
    	exp_res_list = [] #[ True, False.True ]
    

    1、到redis里取出5分钟的值,进行平均运算,得到的结果,与阈值【按定义的运算符】进行比较

    2、拿到,每个表达式的结果,添加到exp_res_list,为什么要拿到结果?因为不是不是最后一条

    3、拼接完整的表达式字符串 exp= "False and True and False and True"

    4、我为什么不在这里顺手就报警了,这样不是很简单?

      你们学过生产消费者模型吗?为了解耦,另外就是异步

      我要考量到报警收敛,我可能一次批量报警,所以我就单独写一个报警模块

    5、将成立的触发发送到报警队列

    3、实现代码

        def load_service_data_and_calulating(self,host_obj,trigger_obj,redis_obj):
            '''
            fetching out service data from redis db and calculate according to each serivce's trigger configuration
            :param host_obj:
            :param trigger_obj:
            :param redis_obj: #从外面调用此函数时需传入redis_obj,以减少重复连接
            :return:
            '''
            #StatusData_1_LinuxCPU_10mins
            self.redis = redis_obj
            calc_sub_res_list= [] #先把每个expression的结果算出来放在这个列表里,最后再统一计算这个列表
            positive_expressions = [] #报警的时候,让用户知道,那些条件导致触发报警器成立
            expression_res_string = '' #最终拼成的表达式运算字符串
            for expression in trigger_obj.triggerexpression_set.select_related().order_by('id'):
                print(expression,expression.logic_type)
                expression_process_obj = ExpressionProcess(self,host_obj,expression)
                single_expression_res = expression_process_obj.process() #得到单条expression表达式的结果
                if single_expression_res:
                    calc_sub_res_list.append(single_expression_res)
                    if single_expression_res['expression_obj'].logic_type: #不是最后一条
                        expression_res_string += str(single_expression_res['calc_res']) + ' ' + 
                                                 single_expression_res['expression_obj'].logic_type + ' '
                    else:
                        expression_res_string += str(single_expression_res['calc_res']) + ' '
    
                    #把所有结果为True的expression提出来,报警时你得知道是谁出问题导致trigger触发了
                    if single_expression_res['calc_res'] == True:
                        single_expression_res['expression_obj'] = single_expression_res['expression_obj'].id #要存到redis里,数据库对象转成id
                        positive_expressions.append(single_expression_res)
                #else: #single expression不成立,随便加个东西,别让程序出错,这个地方我觉得是个bug
                #    expression_res_string += 'None'
            print("whole trigger res:", trigger_obj.name,expression_res_string)
            if expression_res_string:
                trigger_res = eval(expression_res_string)
                print("whole trigger res:", trigger_res )
                if trigger_res:#终于走到这一步,该触发报警了
                    print("##############trigger alert:",trigger_obj.severity,trigger_res)
                    self.trigger_notifier(host_obj,trigger_obj.id, positive_expressions,msg=trigger_obj.name) #msg 需要专门分析后生成, 这里是临时写的
    

    三、故障持续了多久?

    1、开发目标

    2、功能如下:

    1、连接上 redis连接,双方已经是生产这消费者模式

    2、所以我要把传送接口约定好,内容包括

    1. host_id:那台主机
    2. trigger_id:哪一个触发器,
    3. positive_expressions:哪一个表达式触发的报警
    4. msg:消息
    5. time: 什么时候报警的
    6. start_time:什么时间开始的
    7. duration:故障持续多久了

    3、发不到订阅的频道TRIGGER_CHAN = 'trigger_event_channel'

    4、为什么是pickle?

    1. 我的ositive_expressions里面存的是什么东西,是实例
    2. redis里面肯定存不成实例,所以我以字符串的形式存进去,json序列化不了实例

    5、先把之前的trigger加载回来,获取上次报警的时间,以统计 故障持续时间
    6、同时在redis中记录这个trigger , 前端页面展示时要统计trigger 个数
    7、一个trigger 记录5分钟后会自动清除, 为了在前端统计trigger个数用的

    3、代码实现

        def trigger_notifier(self,host_obj,trigger_id, positive_expressions,redis_obj=None,msg=None):
            '''
            all the triggers alerts need to be published through here
            :param host_obj:
            :param trigger_id:
            :param positive_expressions: it's list, contains all the expression has True result
            :param redis_obj:
            :return:
            '''
    
            #alert.sendmail(msg )
            #alert.sendsms(msg)
            if redis_obj: #从外部调用 时才用的到,为了避免重复调用 redis连接
                self.redis = redis_obj
            print("33[43;1mgoing to send alert msg to trigger queue............33[0m")
            print('trigger_notifier argv:',host_obj,trigger_id, positive_expressions,redis_obj)
            #
            msg_dic = {'host_id':host_obj.id,
                       'trigger_id':trigger_id,
                       'positive_expressions':positive_expressions,
                       'msg':msg,
                       'time': time.strftime("%Y-%m-%d %H:%M:%S",time.localtime()),
                       'start_time':time.time() ,
                       'duration':None
                       }
            self.redis.publish(self.django_settings.TRIGGER_CHAN, pickle.dumps(msg_dic))
    
            #先把之前的trigger加载回来,获取上次报警的时间,以统计 故障持续时间
            trigger_redis_key = "host_%s_trigger_%s" % (host_obj.id, trigger_id)
            old_trigger_data = self.redis.get(trigger_redis_key)
            print("old_trigger_data",old_trigger_data)
            if old_trigger_data:
                old_trigger_data = old_trigger_data.decode()
                trigger_startime = json.loads(old_trigger_data)['start_time']
                msg_dic['start_time'] = trigger_startime
                msg_dic['duration'] = round(time.time() - trigger_startime)
    
    
            #同时在redis中纪录这个trigger , 前端页面展示时要统计trigger 个数
    
            self.redis.set(trigger_redis_key, json.dumps(msg_dic), 300) #一个trigger 纪录 5分钟后会自动清除, 为了在前端统计trigger个数用的
  • 相关阅读:
    Debian 8(jessie)下设置系统启动直接进入命令行,无GUI
    Unity 查找物体对象
    Unity的生命周期函数
    Unity脚本实现添加子物体
    Unity工程中 .Meta 文件
    Unity 中简单的第三人称摄像机跟随
    github删除自己的库--Deleting a repository
    TypeScript函数
    Egret引擎学习笔记
    Egret引擎list内单个渲染对象代码编写
  • 原文地址:https://www.cnblogs.com/luoahong/p/9566478.html
Copyright © 2011-2022 走看看