系統監控設計與實現

監控宿主機器的一些基礎指標,並寫入到 influxdb 用於以後的可視化以及報警服務linux

監控的指標包括:cpu利用率,cpu負載,內存使用,網絡負載,iops,磁盤等git

整體設計

go-monitor.png

主要分爲兩大模塊,reportercollectorschedulergithub

  • collector: 負責具體的某些監控指標的採集
  • reporter: 負責將採集到的指標寫入到數據庫
  • scheduler: 負責整個流程的調度,數據採集和數據寫入的協同

collector 將採集到的數據寫到 channel 裏,monitorchannel 中讀取採集到的數據批量寫入到 influxdb 中,整個過程的系統由 scheduler 來調度golang

設計思路

collector 設計

type Metric struct {
    Keys      map[string]string      `json:"keys"`
    Vals      map[string]interface{} `json:"vals"`
    Timestamp time.Time              `json:"timestamp"`
}

metric 是指標數據的抽象,包含三個字段數據庫

  • Keys: 指標的維度,對應 influxdb 中的 tag,主要用於查詢時對數據進行分類,目前只有 host 在該字段中,後面能夠按需添加新的字段
  • Vals: 指標的值,對應 influxdb 中的 field,用於記錄指標具體的值,一條數據中能夠有多個指標,好比 cpu 利用率就有 system/user/idle 三個值,Vals 被設計成 map[string]interface{} 主要是爲了和 influxdb 提供的接口對其,目前只有 float64 類型
  • Timestamp: 指標採集的時間,因爲數據是批量發送,剛生成的數據可能會等待下一條數據一塊兒打包發送,這個時間間隔可能較長,所以在每條數據裏面加上這條數據產生的時間戳,一塊兒發送給 influxdb
type Collector interface {
    Collect() []*Metric
}

全部的數據採集過程抽象成一個 collector 接口,在整個工做流中,這個接口會被週期性調用,每次調用返回一條或多條 metric 數據(目前僅有一條,但可見的拓展需求,好比多網卡或多磁盤的監控就可能返回多條數據)json

func NewCollector(name string, params []interface{}) (Collector, error)

再提供一個工廠方法,經過類名和參數來構造 collectorcentos

reporter 設計

type MetricItem struct {
    Table  string
    Metric *collector.Metric
}

type Reporter interface {
    Report([]*MetricItem) error
}

具體某條數據的寫入到哪一個表中,由 scheduler 經過 MetricItem 告知 reporterapi

reporter 提供一個 Report 供 scheduler 調用,將 mertic 數據打包寫入到數據庫網絡

scheduler 設計

func (s *Scheduler) SetReporter(r reporter.Reporter)
func (s *Scheduler) AddCollector(c collector.Collector, table string, interval time.Duration)
func (s *Scheduler) Scheduler()
func (s *Scheduler) Stop()

主要提供三個接口centos7

  • SetReporter: 設置 reporter,目前只有 influxdb 一個 reporter,目前一個 scheduler 中只有一個 reporter
  • AddCollector: 新增 collector,一個 scheduler 能夠有多個 collecotr
  • Scheduler: 開始調度,這裏會建立數據採集和數據寫入協程,經過 channel 實現協程之間的通訊
  • Stop: 調度結束,中止全部數據採集協程,發送隊列中全部剩餘的數據,而後退出

主要工做流程

  1. 經過配置分別構造 collectorreporterscheduler 對象
  2. 調用 scheduler.AddCollectorscheduler.SetReportercollectorreporter 對象關聯到 scheduler
  3. 調用 scheduler.Scheduler 開始調度,這裏將建立週期執行的 collector 協程,以及負責數據寫入的 reporter 協程
  4. 等待退出信號,退出時,先中止當前的 collector 協程,再等待 reporter 協程退出
c := NewCollector()
r := NewReporter()
s := NewScheduler()

s.AddCollector(c)
s.SetReporter(r)
s.Scheduler()

s.Stop()

reporter 和 collector 的同步

這是一個典型的生成者消費者問題,多個生成者 collector 往一個 channel 中寫入,一個消費者 reporterchannel 中消費數據

須要注意的是,執行退出時,須要將隊列中數據消費完,正確的執行順序應該爲:

  1. collector 中止寫入
  2. 等待全部的 collector 退出
  3. 關閉 channel
  4. 等待 reporter 退出
s.stop = true
s.collectorWG.Wait()
close(s.metricQueue)
s.reporterWG.Wait()

這裏使用兩個 sync.WaitGroup 來同步,分別用於等待 collectorreporter

數據採集

目前主要有 cpu利用率,cpu負載,內存使用,網絡負載,iops,磁盤這些數據的採集,主要使用 github.com/mackerelio/go-osstat 相關接口,這個庫對各個操做系統的監控做了封裝,並提供了統一的便可,linux 下實現基本都是解析 /proc 目錄下系統文件的數據

cpu 利用率

github.com/mackerelio/go-osstat/cpu 下的 Get 接口返回當前總的 cpu 時間(user/system/idle),須要在每次調用減去上一次調用的值,能夠獲得這段時間以內 cpu 時間,這段時間內 user/system/idle 與 total 的比值就是 cpu 利用率

結果應該與 top 命令觀察結果一致

cpu 負載

github.com/mackerelio/go-osstat/loadavg 下的 Get 接口返回 1分鐘,5分鐘,15分鐘內的平均負載,所以直接返回這個接口便可

結果應該與 uptime 命令觀察結果一致

內存使用

github.com/mackerelio/go-osstat/memory 下的 Get 接口返回當前內存的使用狀況,直接返回這個接口便可

結果應該與 free 命令觀察結果一致

網絡負載

github.com/mackerelio/go-osstat/network 下的 Get 接口返回各個網卡下的網絡流量(包括一些虛擬網卡),這裏咱們只關注外網的流量,這個設備名通常是 eth0,centos7 爲了支持多個網卡設備名的惟一性,改爲了以 en 開頭的網卡,所以咱們須要從返回的數據中找到以 en 開頭的那個那個網卡,返回對應的數據

結果應該和 netstat -i 命令觀察結果一致

iops

github.com/mackerelio/go-osstat/disk 下的 Get 接口返回各個磁盤設備總的 io 次數,這裏咱們服務的磁盤,通常是 sda,所以須要先找到 sda,再減去上次的 io 次數,除以時間獲得 iops

磁盤大小

磁盤大小監控直接使用 golang 系統的 api 便可

stats := &syscall.Statfs_t{}
_ = syscall.Statfs("/home", stats)

連接

轉載請註明出處
本文連接: https://tech.hatlonely.com/article/65
相關文章
相關標籤/搜索