zoukankan      html  css  js  c++  java
  • 分布式监控系统(类zabbix)

    目录:

    为什么要做监控?

    监控系统业务需求分析;

    监控系统架构设计;

    监控系统表结构设计;

    一、为什么要做监控系统?

    市面上已经有很多成熟的监控系统,例如zabbix、nagios,为什么自己开发监控系统?

    1.提示个人开发能力;

    2.熟悉成熟监控系统的设计思想、架构、解耦原则;

    3.调用 zabbix/openfalcon/nagios的API进行个人开发定制;

     二、监控系统业务需求分析

    1、可以监控常用系统服务、应用、网络设备等;

    硬件层面:

      服务器温度、磁盘RAID阵列......

    系统层面:

      存活状态、CPU、RAM、load负载

    应用层:

      mysql、Nginx、Django、LVS、HAProxy

    业务层面:

      PV、UV、订单

    2、1台服务器上可以监控N个不同的服务、不同的服务汇报监控数据的时间间隔也不同;(例如CPU负载过高60分钟汇报1次、Nginx服务端口是否关闭3分钟汇报1次)

    3.同1个服务在不同被监控机器的监控间隔、报警的阀值可不同(不同被监控机器的性能不同)

    4.可以批量的给一批机器 添加、删除、修改监控项;

    5.告警级别:

    • 不同的服务 因为业务重要程度不同,如果出了问题可以设置不同的报警级别
    • 可以指定特定的服务或告警级别的事件通知给特定的用户
    • 告警的升级设定
    6.历史数据 的存储和优化
    • 实现用最少的空间占用量存储最多的有效数据
    • 如何做到1s中之内取出一台主机上所有服务的5年的监控数据?(趋势图展示)  

    7.数据可视化,如何做出简洁美观的用户界面?

     
    8.如何实现单机支持5000+机器监控需求?

    6.安装、部署,支持主动/被动监控。

    a.可在client端上安装agent插件,向server端主动汇报监控信息(主动监控)

    b.可以通过server端去抓取client端监控数据(被动监控)

    三、监控系统架构设计

    client 向server 获取自己的监控配置项

    1.server DB存储客户端配置信息
    2.client定时去服务器获取配置信息(更新配置项)


    client 向server 汇报监控数据

    1.客户端通过命令获取返回值
    2.组织数据汇报监控数据给Django,然后Django打时间戳把监控信息存到redis
    3.Django在把监控信息存到redis的同时会触发 1个数据优化存储程序、阀值判断和报警程序
    4.Monitor Data Handler去redis轮训检测哪个主机 没有汇报信息;

    四、监控系统表结构设计

    from django.db import models
    from django.db import models
    from django.contrib.auth.models import User
    
    class Host(models.Model):
        '''被监控主机表  '''
        name=models.CharField(max_length=64,unique=True,verbose_name='主机名') #唯一
        ipaddr=models.GenericIPAddressField(unique=True,verbose_name='IP地址')
        host_groups=models.ManyToManyField('HostGroup',blank=True,verbose_name='主机组')  #1台主机可以同时属于多个whatever 主机组
        templates=models.ManyToManyField('Template',blank=True,verbose_name='所属模板') #主机和模板直接 多 对 多,可以给单台主机 定制模板
        monitored_by_choices = (
            ('agent', 'Agent'),
            ('snmp', 'SNMP'),
            ('wget', 'WGET'),
        )
        monitored_by = models.CharField(max_length=64, choices=monitored_by_choices,verbose_name='监控方式')
        status_choices = (
            (1, 'Online'),
            (2, 'Down'),
            (3, 'Unreachable'),
            (4, 'Offline'),
            (5, 'Problem'),
        )
        status = models.IntegerField(choices=status_choices, default=1,verbose_name='存活状态')
        host_alive_check_interval = models.IntegerField(default=30, verbose_name='主机存活状态检测间隔')
        memo = models.TextField(blank=True,null=True,verbose_name='备注信息')
    
    
    class HostGroup(models.Model):
        '''被监控主机 组  '''
        name =  models.CharField(max_length=64,unique=True)
        templates = models.ManyToManyField("Template",blank=True) #组可以有模板,方便批量管理、操作; 主机也可以有模板
        memo = models.TextField(blank=True,null=True,verbose_name="备注")
    
    
    class ServiceIndex(models.Model):
        '''监控的服务的 正常指标列表'''
        name = models.CharField(max_length=64,verbose_name='指标名称')
        key =models.CharField(max_length=64,verbose_name='cpu idle')
        data_type_choices = (#客户端汇报的监控信息的数据类型
            ('int',"int"),
            ('float',"float"),
            ('str',"string")
        )
        data_type = models.CharField(max_length=32,choices=data_type_choices,default='int',verbose_name='指标数据类型')
        memo = models.CharField(max_length=128,blank=True,null=True,verbose_name="备注")
    
    
    class Service(models.Model):
        '''监控的某项服务'''
        name = models.CharField(max_length=64,unique=True,verbose_name='服务名称')
        interval = models.IntegerField(default=60,verbose_name='监控间隔')
        plugin_name = models.CharField(max_length=64,default='n/a',verbose_name='插件名')
        items = models.ManyToManyField('ServiceIndex',blank=True,verbose_name="指标列表",)#1个CPU服务可能有多个指标
        has_sub_service = models.BooleanField(default=False,help_text="如果一个服务还有独立的子服务 ,选择这个,比如 网卡服务有多个独立的子网卡") #如果一个服务还有独立的子服务 ,选择这个,比如 网卡服务有多个独立的子网卡
        memo = models.CharField(max_length=128,blank=True,null=True,verbose_name="备注",)
    
    
    
    class Template(models.Model):
        name = models.CharField(max_length=64,unique=True,verbose_name='模版名称')
        services = models.ManyToManyField('Service',verbose_name="服务列表")  #1个模板监控多个服务,1个服务属于多个模板
        triggers = models.ManyToManyField('Trigger',verbose_name="触发器列表",blank=True)#哪个服务
    
    
    
    
    
    class TriggerExpression(models.Model):
        '''
         触发器表达式
         if cpu.idle(avg(5mins)) < 80% and
         cpu.iowait(hit(10,3)) > 50%  = warning
    
         1 trigger1   cpu.idle(avg(5mins)) < 80% and
         2 trigger1  cpu.iowait(hit(10,3)) > 50%
         通过trigger关联:查询出当前trigger的所有触发器表达式,从上到下按顺序执行!
    
    
        '''
        trigger = models.ForeignKey('Trigger',verbose_name="所属触发器")  #1个触发器表方式(条件)只能属于1个触发器
        service = models.ForeignKey(Service,verbose_name="关联服务")
        service_index = models.ForeignKey(ServiceIndex,verbose_name="关联服务指标")
        specified_index_key = models.CharField(verbose_name="只监控专门指定的指标key",max_length=64,blank=True,null=True)
        operator_type_choices = (('eq','='),('lt','<'),('gt','>'))
        operator_type = models.CharField("运算符",choices=operator_type_choices,max_length=32)
        data_calc_type_choices = (
            ('avg','Average'),
            ('max','Max'),
            ('hit','Hit'),
            ('last','Last'),
        )
        data_calc_func= models.CharField(verbose_name="数据处理方式",choices=data_calc_type_choices,max_length=64)
        data_calc_args = models.CharField(verbose_name="函数传入参数",help_text="若是多个参数,则用,号分开,第一个值是时间",max_length=64)
        threshold = models.IntegerField(verbose_name="阈值")
    
    
        logic_type_choices = (('or','OR'),('and','AND'))
        logic_type = models.CharField(verbose_name="与一个条件的逻辑关系",choices=logic_type_choices,max_length=32,blank=True,null=True)
    
        class Meta:
            pass #unique_together = ('trigger_id','service')
    
    class Trigger(models.Model):
        '''触发器表  '''
        name = models.CharField(u'触发器名称',max_length=64)
        severity_choices = (
            (1,'Information'),
            (2,'Warning'),
            (3,'Average'),
            (4,'High'),
            (5,'Diaster'),
        )
        #expressions = models.ManyToManyField(TriggerExpression,verbose_name=u"条件表达式")
        severity = models.IntegerField(u'告警级别',choices=severity_choices)
        enabled = models.BooleanField(default=True)
        memo = models.TextField(verbose_name="备注",blank=True,null=True)
    
    
    
    
    
    
    class Action(models.Model):
        '''报警方式  '''
        name =  models.CharField(max_length=64,unique=True)
        host_groups = models.ManyToManyField('HostGroup',blank=True)
        hosts = models.ManyToManyField('Host',blank=True)
        triggers = models.ManyToManyField('Trigger',blank=True,help_text="想让哪些trigger触发当前报警动作")
        interval = models.IntegerField(u'告警间隔(s)',default=300)
        operations = models.ManyToManyField('ActionOperation',verbose_name='允许报警升级的设置!')
    
        recover_notice = models.BooleanField(u'故障恢复后发送通知消息',default=True)
        recover_subject = models.CharField(max_length=128,blank=True,null=True)
        recover_message = models.TextField(blank=True,null=True)
        enabled = models.BooleanField(default=True)
    
    class ActionOperation(models.Model):
        name =  models.CharField(max_length=64)
        step = models.SmallIntegerField(verbose_name="第n次告警",default=1)
        action_type_choices = (
            ('email','Email'),
            ('sms','SMS'),
            ('script','RunScript'),
        )
        action_type = models.CharField(verbose_name="动作类型",choices=action_type_choices,default='email',max_length=64)
        notifiers= models.ManyToManyField('UserProfile',verbose_name="通知对象",blank=True)
        _msg_format = '''Host({hostname},{ip}) service({service_name}) has issue,msg:{msg}'''
    
        msg_format = models.TextField(verbose_name="消息格式",default=_msg_format)
    
    
    
    class Maintenance(models.Model):
        '''预维护计划  '''
        name =  models.CharField(max_length=64,unique=True)
        hosts = models.ManyToManyField('Host',blank=True)
        host_groups = models.ManyToManyField('HostGroup',blank=True)
        content = models.TextField(verbose_name="维护内容")
        start_time = models.DateTimeField()
        end_time = models.DateTimeField()
    
    
    class UserProfile(models.Model):
        user = models.OneToOneField(User)
        name = models.CharField(max_length=32)
        phone = models.BigIntegerField(blank=True,null=True)
        weixin = models.CharField(max_length=64,blank=True,null=True)
        email = models.EmailField(blank=True,null=True)
    models.py

    五、项目实战

    5.1:监控客户端开发

    功能:

    1.监控客户端定时向server端更新监控配置信息;

    2.server端响应client{插件名称:汇报间隔},客户端 定期执行该插件向server端汇报监控数据(开始监控);

    5.2:接收监控数据汇报API开发

    功能

    1.server端接收到监控数据之后 加上时间戳,存入redis,并进行数据优化存储;(优化:计算N个点的平均值、max、min、中位数,合并N个点为1个点)

    2.存储优化数据之后,定时 遍历实时数据和触发器正在做对比,判断是否需要触发报警?触发报警通过redis队列发布一条消息到报警中心;

    5.3:报警中心开发

    功能

    1.报警信息汇报之后,信息优化存储、对比触发器阈值,触发报警;(每次客户端主动汇报监控信息时,被动触发。)

    2.主动监测客户端是否按时向server端汇报数据?报警信息合并、收敛;(主动触发报警)

    3.根据不同报警通知到相关责任人

    5.4: 图表展示优化后的监控数据

    参考:

    https://www.cnblogs.com/alex3714/articles/5450798.html

  • 相关阅读:
    c#调用dll,::CoInitialize(NULL)出错
    使用 Anthem.NET 的常见回调(Callback)处理方式小结
    主题和皮肤学习
    得到任意网页源代码 (利用WebClient和WebRequest类)
    HTML marquee标签详解
    制作一个简单的天气预报
    CSS中的类class和标识id选择符(.和#号)
    String split '.'
    Map 的 clear() 方法会清空 Map对象
    sqLite 执行查询语句时报错__及SimpleCursorAdapter
  • 原文地址:https://www.cnblogs.com/sss4/p/9375595.html
Copyright © 2011-2022 走看看