sss4

目录:

为什么要做监控?

监控系统业务需求分析;

监控系统架构设计;

监控系统表结构设计;

 

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

市面上已经有很多成熟的监控系统,例如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

分类:

技术点:

相关文章:

  • 2021-12-06
  • 2021-06-25
  • 2021-11-23
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2021-11-30
  • 2021-06-20
  • 2021-11-07
  • 2022-02-18
  • 2021-11-30
相关资源
相似解决方案