分布式監控系統(類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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM