系统监控设计与实现

监控宿主机器的一些基础指标,并写入到 influxdb 用于之后的可视化以及报警服务

监控的指标包括:cpu利用率,cpu负载,内存使用,网络负载,iops,磁盘等

总体设计

go-monitor.png

主要分为两大模块,reportercollectorscheduler

  • collector: 负责具体的某些监控指标的采集
  • reporter: 负责将采集到的指标写入到数据库
  • scheduler: 负责整个流程的调度,数据采集和数据写入的协同

collector 将采集到的数据写到 channel 里,monitorchannel 中读取采集到的数据批量写入到 influxdb 中,整个过程的系统由 scheduler 来调度

设计思路

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 数据(目前仅有一条,但可见的拓展需求,比如多网卡或多磁盘的监控就可能返回多条数据)

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

再提供一个工厂方法,通过类名和参数来构造 collector

reporter 设计

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

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

具体某条数据的写入到哪个表中,由 scheduler 通过 MetricItem 告知 reporter

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()

主要提供三个接口

  • 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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容