什么是 Prometheus?

Prometheus 是由 SoundCloud 开发的开源监控报警系统和时序列数据库(TSDB),Prometheus 使用 Go 语言开发,是 Google BorgMon 监控系统的开源版本。

什么是 Grafana?

Grafana 是一个跨平台的开源的度量分析和可视化工具,可以通过将采集的数据查询然后可视化的展示,并及时通知。

Prometheus & Grafana 能做什么

简单来说,Prometheus 提供数据指标,Grafana 负责对这些数据指标进行特定形式的展示,就像我们去海鲜市场,左边是卖海鲜的,右边是处理烹饪海鲜的,完美 CP 无疑。

这里不再去赘述两个应用的安装,都是 Go 开发的,所以跑起来非常容易,而且基础的配置可以让你在 Grafana 上选择了 Prometheus 为数据源之后快速的能够看到对应的数据,社区里有很多针对不同服务的exporter,这里我们仅围绕自定义指标进行说明。

首先我们需要先了解一下 Prometheus 客户端提供的四种核心的度量类型

标准度量类型

1、Counter - 累加的指标

Counter 是一个计数器,表示一种累加型指标,该指标只能单调递增或在重新启动时重置为零,比如可以计算累计的请求书、Jenkins 完成任务的成功或者失败的数量。

2、 Gauge - 可增可减的指标

Gauge 是最简单的度量类型,只有一个简单的返回值,可增可减,也可以set为指定的值,Gauge 通常用于反映当前状态,比如当前内存使用情况。

3、Histogram - 自带buckets区间用于统计分布的直方图

Histogram 主要用于在设定的分布范围内(Buckets)记录大小或者次数。

例如请求响应时间:0-100ms、100-200ms、200-300ms、>300ms 的分布情况,Histogram会自动创建3个指标,分别为:

  • 事件发送的总次数_count:比如当前一共发生了2次请求
  • 所有事件产生值的大小的总和_sum:比如发生的2次请求总的响应时间为150ms
  • 事件产生的值分布在bucket中的次数_bucket{le="上限"}:比如响应时间0-100ms的请求1次,100-200ms的请求1次,其他的0次

4、Summary - 数据分布统计图

Summary和Histogram类似,都可以统计事件发生的次数或者大小,以及其分布情况。

Summary和Histogram都提供了对于事件的计数_count以及值的汇总_sum,因此使用_count,和_sum时间序列可以计算出相同的内容。

同时Summary和Histogram都可以计算和统计样本的分布情况,比如中位数,n分位数等等。不同在于Histogram可以通过histogram_quantile函数在服务器端计算分位数。 而Sumamry的分位数则是直接在客户端进行定义。因此对于分位数的计算。 Summary在通过PromQL进行查询时有更好的性能表现,而Histogram则会消耗更多的资源。相对的对于客户端而言Histogram消耗的资源更少。

作业和实例

在 Prometheus 中,一个可以拉取数据的端点IP:Port叫做一个实例(instance),而具有多个相同类型实例的集合称作一个作业(job)

自定义指标的两种方式

  1. 通过 textfiles 收集器进行收集上报
  2. 通过自定义exporter提供一个实例进行上报

一、使用 textfiles 收集器收集内存数据并展示

通过如下命令可以获得内存的可用量

top -bn 1 -i -c| head -n 5| tail -n 1| awk '{print $9}'

node_exporter目录新建textfiles目录

mkdir textfiles

标准的textfiles

# HELP get_available_mem get available mem test case
# TYPE get_available_mem gauge
get_available_me 624

我们采用了gauge可增可减的指标,因为内存是上下浮动变化的,node_expoter会根据设置的时间来定时的读取这个文件的内容,所以我们只需要通过结合crontab来定时更新文件的内容即可

写一个get_available_mem.sh脚本来提供文件内容

#!/bin/sh
#
# * * * * * zoker /bin/bash /home/zoker/app/node_exporter/get_available_mem.sh > /home/zoker/app/node_exporter/get_available_mem.prom
#
echo "# HELP get_available_mem get available mem test case"
echo "# TYPE get_available_mem gauge"
freeme=`top -bn 1 -i -c| head -n 5| tail -n 1| awk '{print $9}' | sed 's/.*\(...\)$/\1/'`
echo "get_available_me $freeme"

这里我们为了能够展现出变化,通过sed命令取了后三位,配置到crontab

vi /etc/crontab
* * * * * zoker /bin/bash /home/zoker/app/node_exporter/get_available_mem.sh > /home/zoker/app/node_exporter/get_available_mem.prom

这样就会定时的更新get_available_mem.prom文件的内容了,这个时候我们来配置 Grafana 的显示

输入图片说明

可以看到刚刚添加的指标会自动出现在 Metrics 的选项里,选择即可看到图形的变化。

二、编写expoter收集随机数并展示

这里以Golang为例,使用 Prometheus 提供的 Golang SDK 编写,下面是一个使用包里面提供的自有 Handler 来暴露一些基本的 Golang 信息的 Exporter:

package main

import (
    "flag"
    "log"
    "net/http"

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

var addr = flag.String("listen-address", ":9192", "The address to listen on for HTTP requests.")

func main() {
    flag.Parse()
    http.Handle("/metrics", promhttp.Handler())
    log.Fatal(http.ListenAndServe(*addr, nil))
}

执行go mod init maingo build self_exporter.go并执行,访问http://127.0.0.1:9192/metrics可看到如下信息

# HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 4.7424e-05
go_gc_duration_seconds{quantile="0.25"} 4.7424e-05
go_gc_duration_seconds{quantile="0.5"} 4.7424e-05
go_gc_duration_seconds{quantile="0.75"} 4.7424e-05
go_gc_duration_seconds{quantile="1"} 4.7424e-05
go_gc_duration_seconds_sum 4.7424e-05
go_gc_duration_seconds_count 1
# HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge
go_goroutines 8
....

是不是感觉很熟悉,上面我们使用textfile方式自定义指标的时候也是这样的格式,这里还只是默认的一些指标,下面我们添加一个 Gauge 类型的指标,提供一些随机的数值

package main

import (
    "flag"
    "log"
    "net/http"
    "math/rand"
    "time"

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

var addr = flag.String("listen-address", ":9192", "The address to listen on for HTTP requests.")

func main() {
    flag.Parse()
    addRandNumbers() //调用函数
    http.Handle("/metrics", promhttp.Handler())
    log.Fatal(http.ListenAndServe(*addr, nil))
}

func addRandNumbers() { // 起一个协程用来定时更新这个 randGauge
    go func() {
        for {
            randGauge.Set(rand.Float64() * 100)
            time.Sleep(2 * time.Second)
        }
    }()
}

var ( // 定义一个 Gauge 类型的可变指标
    randGauge = promauto.NewGauge(prometheus.GaugeOpts{
        Name: "test_random_numbers",
        Help: "test random numbers",
    })
)

重新编译运行,可以看到已经有相关数值了

输入图片说明

我们把这个自定义的exporter配置为 Prometheus 的一个实例

  - job_name: 'jmaster'
    static_configs:
    - targets: ['192.168.31.180:9100', '192.168.31.180:9192']
      labels:
        instance: jmaster

不要忘记重启 Prometheus ,我们进入到 Grafana 即可在 Metrics 看到我们刚刚添加的随机数指标(真是一对好CP)

输入图片说明

总结

通过以上两种方式我们不仅可以使用 Grafana 来进行监控,还可以进行一些数据的展示,毕竟 Grafana 本身就是一个数据度量展示的平台,比如:

  • 注册用户数、创建仓库数量、网站浏览量等
  • Jenkins 构建任务成功失败数(有插件了
  • 访客数量、评论数量
  • 个人推送数据、代码量、工作效能度量展示
  • …..
Blog Logo

Zoker


Published

Image

Zoker's Blog

专注、沉淀、提升

Back to Overview