一、需求讨论

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("\033[43;1mgoing to send alert msg to trigger queue............\033[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个数用的

分布式监控系统开发【day38】:报警阈值程序逻辑解析(三)的更多相关文章

  1. Python之路,Day20 - 分布式监控系统开发

    Python之路,Day20 - 分布式监控系统开发   本节内容 为什么要做监控? 常用监控系统设计讨论 监控系统架构设计 监控表结构设计 为什么要做监控? –熟悉IT监控系统的设计原理 –开发一个 ...

  2. 分布式监控系统开发【day38】:报警自动升级代码解析及测试(八)

    一.报警自动升级代码解析 发送邮件代码 def action_email(self,action_obj,action_operation_obj,host_id,trigger_data): ''' ...

  3. 分布式监控系统开发【day37】:需求讨论(一)

    本节内容 为什么要做监控? 常用监控系统设计讨论 监控需求讨论 如何实现监控服务器的水平扩展? 监控系统架构设计 一.为什么要做监控? 熟悉IT监控系统的设计原理 开发一个简版的类Zabbix监控系统 ...

  4. Python之分布式监控系统开发

    为什么要做监控? –熟悉IT监控系统的设计原理 –开发一个简版的类Zabbix监控系统 –掌握自动化开发项目的程序设计思路及架构解藕原则 常用监控系统设计讨论 Zabbix Nagios 监控系统需求 ...

  5. day26 分布式监控系统开发

    本节内容 为什么要做监控? 常用监控系统设计讨论 监控系统架构设计 监控表结构设计 为什么要做监控? –熟悉IT监控系统的设计原理 –开发一个简版的类Zabbix监控系统 –掌握自动化开发项目的程序设 ...

  6. 分布式监控系统开发【day38】:报警策略设计(二)

    一.策略和动作多对多的好处坏处 1.好处: 相同服务,相同策略的服务可以不用重复写好多次触发器 2.坏处: 1.策略A给小李和小罗发邮件2.策略B给小胡和小崔发邮件3.策略A是第三部发邮件4.策略B是 ...

  7. 分布式监控系统开发【day38】:报警策略队列处理(五)

    一.目录结构 二.报警策略队列处理 1.入口MonitorServer import os import sys if __name__ == "__main__": os.env ...

  8. 分布式监控系统开发【day38】:主机存活检测程序解析(七)

    一.目录结构 二.入口 1.文件MonitorServer.py import os import sys if __name__ == "__main__": os.enviro ...

  9. 分布式监控系统开发【day38】:监控trigger表结构设计(一)

    一.需求讨论 1.zabbix触发器的模板截图 1.zabbix2.4.7 2.zabbix3.0 2.模板与触发器关联的好处 好处就是可以批量处理,比如我说我有1000机器都要监控cpu.内存.IO ...

随机推荐

  1. c/c++ 网络编程 getaddrinfo 函数

    网络编程 getaddrinfo 函数 解析网址,返回IP地址. 例子: #include <iostream> #include <string.h> #include &l ...

  2. git执行cherry-pick时修改提交信息

    git执行cherry-pick时修改提交信息 在本地分支执行cherry-pick命令时有时需要修改commit message信息,可以加参数-e实现: git cherry-pick -e co ...

  3. 文件比较命令(comp)

    comp命令: // 描述: 逐字节比较两个文件或文件集的内容. 如果在没有参数的情况下使用,comp会提示你输入要比较的文件. // 语法: comp [<Data1>] [<Da ...

  4. LinuxCPU性能监控工具---mpstat

    mpstat是 Multiprocessor Statistics的缩写,是实时系统监控工具.其报告与CPU的一些统计信息,这些信息存放在/proc/stat文件中.在多CPU系统里,其不但能查看所有 ...

  5. docker容器日志收集方案汇总评价总结

    docker日志收集方案有太多,下面截图罗列docker官方给的日志收集方案(详细请转docker官方文档).很多方案都不适合我们下面的系列文章没有说. 经过以下5篇博客的叙述简单说下docker容器 ...

  6. IDEWorkspaceChecks.plist文件是干什么用的?

    在提交PR的时候,无意间发现了在xcworkspace/xcshareddata中多了一个名为IDEWorkspaceChecks.plist的文件.自己并没有手动创建此文件,在网上查了一下,最终对其 ...

  7. formatter的使用

    1.目的 如图所示,实现行编辑栏中的编辑删除,以及在时间建议中显示上中下旬 可参考easyui官方文档中所写的关于datagrid列属性:http://www.jeasyui.net/plugins/ ...

  8. 关于模块安装及cmd安装pip3模块失败的 Read timed out.的补救方法

    自己在安装pip中的request模块时,安装到一半老是报错.我看了下报错的代码最后一句写的是 Read timed out. 就是读取超时,从网上查了一下,原因是由于中国的网比较慢,下载超时.需要在 ...

  9. ERROR in static/js/0.5d7325513eec31f1e291.js from UglifyJs

    今天把vue项目打包是遇到这个问题.这是在服务器上打包时报的错误,本地打包不报错!很头疼!上网查了很多,发现有很多人和我遇到类似的问题,但是都没有解决我的问题!后来灵机一动,解决问题,这就跟大家说一下 ...

  10. Java中的CAS原理

    前言:在对AQS框架进行分析的过程中发现了很多CAS操作,因此有必要对CAS进行一个梳理,也便更清楚的了解其原理. 1.CAS是什么 CAS,是compare and swap的缩写,中文含义:比较交 ...