目錄:
為什么要做監控?
監控系統業務需求分析;
監控系統架構設計;
監控系統表結構設計;
一、為什么要做監控系統?
市面上已經有很多成熟的監控系統,例如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.告警級別:
- 不同的服務 因為業務重要程度不同,如果出了問題可以設置不同的報警級別
- 可以指定特定的服務或告警級別的事件通知給特定的用戶
- 告警的升級設定
- 實現用最少的空間占用量存儲最多的有效數據
- 如何做到1s中之內取出一台主機上所有服務的5年的監控數據?(趨勢圖展示)
7.數據可視化,如何做出簡潔美觀的用戶界面?
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)
五、項目實戰
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: 圖表展示優化后的監控數據
參考:
