golang学习笔记-基于promethues客户端的数据统计

本文主要介绍基于promethues的go统计功能,利用promethues配合grafana进行实时数据的展示。因此promethues和promethues的测试功能是以docker的形式存在,并且以默认的方式启动docker,并不能用于实际的生产环境中。

1.promethues的docker环境准备

这里使用了promethues的service和exporter两部分。exporter类似一个代理,安装了exporter的机器可以将配置的需要采集的信息发送给service,service集中展示各个exporter发送来的数据。分两部分来介绍docker下的promethues简单使用。

1.1 拉去镜像

1.1.1 promethues的最新的docker镜像
docker pull prom/prometheus
1.1.2 promethues的exporter最新的镜像
docker pull prometheusnet/docker_exporter

1.2启动docker镜像

1.2.1 启动service
docker run --name myprometheus -p 9090:9090 -d prom/prometheus
或者
docker run -v /home/prometheus/prometheus.yml:/etc/prometheus/prometheus.yaml --name myprometheus -p 9090:9090 -d prom/prometheus

启动了一个容器名为myprometheuspromethues的docker容器,映射本地端口9090到docker容器的9090端口。无误启动之后在浏览器上查看promethues的9090端口是否有自带的监控界面出现,输入http://ip地址:9090后,如下如则说明promethues已经安装正常。

https://raw.githubusercontent.com/luciferofwg/picgo/master/img/github.com/picgoimage-20200820154027702.png

1.2.2 启动exporter
docker run --name mynode-exporter -p 9100:9100 -d prom/node-exporter

启动了一个容器名为mynode-exporternode-exporter的docker容器,映射本地端口9100到docker容器的9100端口。9100端口是exporter镜像的数据发送端口,当在一台机器上启动多个exporter的时候需要规划好端口,防止端口冲突。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3CCZvSkm-1597976803357)()]

启动后我们在同一局域网的一台机器上查看已经启动的exporter的9100端口是否有数据产生。在浏览器输入http://ip地址:9100/metrics,如下图所示,说明exporter已经有采集的数据产生。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sPiGsMwR-1597976803358)()]

1.2.3 service展示exporter的数据

将第2)步的exporter增加到service中,为了能够在service中显示exporter的数据。需要在service中的配置文件promethues.yaml中增加exporter的信息。因为启动的myprometheus容器是没有挂载到宿主机磁盘的,因此需要进入该容器内部修改,操作如下:

  • 执行docker exec -it myprometheus sh进入容器

  • 打开promethues.yaml文件,执行vi /etc/prometheus/prometheus.yml,在scrape_configs下增加一组job_name,增加完入下图:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mZwAZkWu-1597976803360)()]

红色部分为新增的名为node节点配置,targets地址填写exporter的映射地址。第2)步中为localhost:9100,我们在这直接将宿主机的ip地址替换了localhost,到此就将新的exporter增加到了service中。

  • 在promethues的docker-bash中执行exit退出docker容器,然后执行docker restart 容器ID重启service

重启完后再看一下promethues的监控页面,打开http://172.20.35.40:9090,点击Status菜单栏下的targets,就可以看到增加的exporter了,如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-06WHeW0j-1597976803362)()]

2.go程序实现的exporter

2.1 promethues客户端

promethues是一个开源的分布式监控软件,除了使用自身的service和exporter外,也提供了一些客户端api,供二次开发使用。官方提供的客户端有下面:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VrPx1eX0-1597976803364)()]

这里使用的是client_golang客户端,目的是通过客户端将这个程序的一些数据写入到promethues中,并且在promethues或者grafana中实时显示这些数据。

在这个程序中加载下面两个包:

"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"

promethues的客户端提供了4种数据:CounterGaugeHistogramSummary。分别对应“累加指标”、“测量指标”、“直方图”和“概略图”。

counter:随着时间值会增长。比如:某个数据的数据量,运行发生的错误次数,持续增加的数据包等。

Gauge:代表了采集的单个数据,这个数据可以增加也可以减少。比如cpu的使用率,内存的使用率,硬盘的容量等。

HistogramSummary:这两种的使用频率稍小,这两个都是基于采样的的方式。使用者两个时会产生多组数据,_count表示采样的总数,_sum表示采样的总和,_bucket表示落入此范围的数据。

2.2 go代码实现

定义client_golang`中的四种数据类型的对象实例。

var (
	MyTestCounter = prometheus.NewCounter(prometheus.CounterOpts{
		//因为Name不可以重复,所以建议规则为:"部门名_业务名_模块名_标量名_类型"
		Name: "my_test_counter", //唯一id,不可重复Register(),可以Unregister()
		Help: "my test counter", //对此Counter的描述
	})
	MyTestGauge = prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "my_test_gauge",
		Help: "my test gauge",
	})
	MyTestHistogram = prometheus.NewHistogram(prometheus.HistogramOpts{
		Name:    "my_test_histogram",
		Help:    "my test histogram",
		Buckets: prometheus.LinearBuckets(20, 5, 5), //第一个桶20起,每个桶间隔5,共5个桶。 所以20, 25, 30, 35, 40
	})
	MyTestSummary = prometheus.NewSummary(prometheus.SummaryOpts{
		Name:       "my_test_summary",
		Help:       "my test summary",
		Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}, //返回五分数, 九分数, 九九分数
	})
)

将上面定义的四种数据实例对象注册到promethues上。promethues提供了两种注册方式,MustRegisterRegisterRegister能够捕获注册时的错误。下面是注册的过程:

//不能注册多次Name相同的Metrics
//MustRegister注册失败将直接panic(),如果想捕获error,建议使用Register()
if err := prometheus.Register(MyTestCounter); err != nil {
    log.Fatal(err)
}
prometheus.MustRegister(MyTestGauge)
prometheus.MustRegister(MyTestHistogram)
prometheus.MustRegister(MyTestSummary)

为了模拟数据,再增加一个goroutine函数。不断的向这四种数据实例上写数据,如下:

go func() {
    var i float64
    for {
        i++
        MyTestCounter.Add(10000)                                                  //每次加常量
        MyTestGauge.Add(i)                                                        //每次加增量
        MyTestHistogram.Observe(30 + math.Floor(120*math.Sin(float64(i)*0.1))/10) //每次观察一个18 - 42的量
        MyTestSummary.Observe(30 + math.Floor(120*math.Sin(float64(i)*0.1))/10)

        time.Sleep(time.Second)
    }
}()

注册后将这个实现的exporter导出到指定的端口,这个端口用于promethues的service端采集数据。在这里我们使用go的net/http包导出,如下:

http.Handle("/metrics", promhttp.Handler())
log.Fatal(http.ListenAndServe("0.0.0.0:7070", nil)) //多个进程不可监听同一个端口

之后编译运行该程序,待程序运行后,在本地的浏览器或者终端上应该可以查看到该exporter产生的数据。在浏览器中输入http://127.0.0.1:7070/metrics或者在终端中输入culr http://127.0.0.1:7070/metrics查看,浏览器结果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GKFHmAbQ-1597976803364)()]

2.3 添加到promethues-service中

上一步完成之后实现的exporter已经产生了采集数据,但是还没有在promethues的service上显示。需要在service上进行一些配置,之后就可以显示了。

进入已经启动的service-docker镜像中,打开promethues.yaml文件,在scrape_configs下增加一组job_name,将自定义的exporter端口加进去,增加完入下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GWu52jBh-1597976803365)()]

红色部分表示:定一个一个名为gotest的job任务,目标地址是172.20.35.2:7070,因为这个测试程序不是运行在服务器上的,而是在另一台机器上,所以要使用程序运行的ip和对应的端口。

配置完成之后退出docker容器并重启promethues的service容器。然后重新打开promethues的service数据监控页面,就能看到新添加的名为gotest的job节点。如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lJcj744b-1597976803367)()]

2.4 grafana显示数据

使用promethues自带的检测工具显示采集到的数据是可以的,但是和另一个开源工具grafana比较起来就稍微差一点,promethues自带的数据展示示例如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bdOiKW3Q-1597976803368)()]

我们在已经安装好的grafana上展示基于golang客户端采集的数据,分别根据四种数据类型展示对应的视图。但是这个数据和程序的编写的数据看的不是跟清楚,这一点我们在下一章节详细处理这个问题,暂时先把路走通。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YjPssLyR-1597976803369)()]

3.采集系统信息的示例

编写一个基于promethues的client_golang客户端程序,这个程序能够采集当前运行机器的cpu使用率,采集虚拟内存的使用情况,并且将这些数据在grafana上展示出来。

3.1 实例代码

3.1.1 定义实例对象
var (
	MyTestCounter = prometheus.NewCounter(prometheus.CounterOpts{
		//因为Name不可以重复,所以建议规则为:"部门名_业务名_模块名_标量名_类型"
		Name: "demo3_counter",     //唯一id,不可重复Register(),可以Unregister()
		Help: "this is a counter", //对此Counter的描述
	})
	MyTestGauge = prometheus.NewGauge(prometheus.GaugeOpts{
		Name: "demo3_gauge",
		Help: "this is a gauge",
	})
	memGauge = prometheus.NewGaugeVec(prometheus.GaugeOpts{
		Name: "demo3_mem_gauge_vec",
		Help: "this is a mem gauge_vec",
	}, []string{
		"percent",
	})
)

MyTestCounter是单个的增长值,记录一个数,每次增加100。MyTestGauge是瞬时值,记录当前的cpu使用率。memGauge同样是瞬时值,但是定义了一个gauge的矢量,注意定义时的函数。

3.1.2 注册实例对象
if err := prometheus.Register(MyTestCounter); err != nil {
		logger.Fatal(err)
	}
	if err := prometheus.Register(MyTestGauge); err != nil {
		logger.Fatal(err)
	}
	if err := prometheus.Register(memGauge); err != nil {
		logger.Fatal(err)
	}

使用Register捕获错误,防止由于定义实例对象时可能的名字一致导致的常见错误。

3.1.3 定义获取数据
go func() {
		for {
			select {
			case <-tick.C:
				MyTestCounter.Add(100)

				totalPercent, _ := cpu.Percent(time.Second*1, false)
				MyTestGauge.Set(totalPercent[0])
				logger.Printf("CPU use precent:[%v]", totalPercent[0])

				memInfo, _ := mem.VirtualMemory()
				memGauge.WithLabelValues("total").Set(float64(memInfo.Total))
				memGauge.WithLabelValues("used").Set(float64(memInfo.Used))
				memGauge.WithLabelValues("Available").Set(float64(memInfo.Available))
				logger.Printf("virtual memory total:[%v], used:[%v], free:[%v]", memInfo.Total, memInfo.Used, memInfo.Available)
			}
		}
	}()

定义了一个func,在定时器里面对实例MyTestCounter模拟增加100。获取cpu使用率和获取虚拟内存的值,并将值用标签函数WithLabelValues增加到实例对象中。

3.1.4 监听/metrics
	http.Handle("/metrics", promhttp.Handler())
	logger.Fatal(http.ListenAndServe("0.0.0.0:5050", nil))

在4040端口上发布这些数据,供promethues的service端查询数据。

3.2 运行

3.2.1 运行服务并查看数据

直接编译程序后启动程序,在浏览器中输入http://ip:5050/metrics查看是否有数据产生,如下:
在这里插入图片描述

3.2.2 配置promethues的service

修改docker中promethues的service端,将新的5050端口加到配置文件中,重启docker容器。在promethues的service9090端口上应该能看到该节点的数据,如下:
在这里插入图片描述

3.3 grafana配置

grafana的配置比较多,在别处单独说明,在这个地方展示一下已经配置好的图形。

3.3.1 cpu使用率

左边的仪表盘记录的cpu瞬时使用率,右边部分记录了cpu的历史使用率。
在这里插入图片描述

3.3.2 虚拟内存使用情况

三种内存的数据。
在这里插入图片描述

3.3.3 count的累加

在这里插入图片描述

4.某代码

定义的state实例对象:

CPUTest = New().WithState("cpu_gauge", []string{"cpu", "gauge"})

state实例的实现函数:

func (this *Prom) WithState(name string, lables []string) *Prom {
	if this == nil || this.state != nil {
		return this
	}
	this.state = prometheus.NewGaugeVec(
		prometheus.GaugeOpts{
			Name: name,
			Help: name,
		}, lables)
	prometheus.MustRegister(this.state)
	return this
}

其实就是定义了一个gauge对象,使用带有lable的函数将数据写到对应的name中去。每一个数据带有一个lable

将采集到的cpu数据通过CPUTest实例写到prometheus中的代码:

stat.CPUTest.State("name1", int64(totalPercent[0]), "extra1")

grafana中的图形数据:
在这里插入图片描述
在grafana上显示了这个数据的一些信息,解析数据的描述信息。
cpu_gauge:是定义gauge实例时的名称,对应GaugeOpt{}中的name字段。
cpu="name1":是标签的名字
gague="extra1":是额外额拓展字段名字
job="exporter_demo1":是这个prometheusexporterservice配置文件中的名字

修改一下调用处的函数:

go func() {
	for {
		totalPercent, _ := cpu.Percent(time.Second*1, true)
		for index, precent := range totalPercent {
			stat.CPUTest.State(fmt.Sprintf("cpu-%v", index), int64(precent), "realtime")
		}

		time.Sleep(time.Second)
	}
	}()

grafana的图像:
在这里插入图片描述采集各个cpu的数据,并将每一个cpu的数据据都显示出来。
标签名cpu="cpu-0"gauge显示了固定的字符串。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值