Grafana & prometheus 入门

735 阅读10分钟

Background

公司使用 Prometheus 和 Grafana 来对线上服务进行监控,这篇文章希望介绍一下这两个工具,并用简单的例子来学习一下这两个工具的使用方法

Prometheus简介

Prometheus由SoundCloud发布,是一套由go语言开发的开源的监控&报警&时间序列数据库的组合。

Prometheus的基本原理是通过HTTP协议周期性抓取被监控组件的状态,任意组件只要提供对应的HTTP接口就可以接入监控。不需要任何SDK或者其他的集成过程。这样做非常适合做虚拟化环境监控系统,比如VM、Docker、Kubernetes等。

输出被监控组件信息的HTTP接口被叫做exporter。目前互联网公司常用的组件大部分都有exporter可以直接使用,比如Varnish、Haproxy、Nginx、MySQL、Linux系统信息(包括磁盘、内存、CPU、网络等等)。

基本架构

image.png Prometheus 主要的组件功能如下:

  • Prometheus Server:server的作用主要是定期从静态配置的targets或者服务发现(主要是DNS、consul、k8s、mesos等)的 targets 拉取数据。
  • Exporter: 主要负责向prometheus server做数据汇报。而不同的数据汇报由不同的exporters实现,比如监控主机有node-exporters,mysql有MySQL server exporter。
  • Pushgateway:Prometheus获得数据的方式除了到对应exporter去Pull,还可以由服务先Push到pushgateway,server再去pushgateway 拉取。
  • Alertmanager:实现prometheus的告警功能。
  • webui:主要通过grafana来实现webui展示。

我们在实际使用的时候的基本流程就是:

各个服务push监控数据到其对应的指标(比如下面提到的http_requests_total) --> Prometheus Server定时采集数据并存储 --> 配置Grafana展示数据 & 配置告警规则进行告警

常用指标

Prometheus 存储的是时序数据, 即按照相同时序(相同的名字和标签),以时间维度存储连续的数据的集合。时序(time series) 是由名字(Metric),以及一组 key/value 标签定义的,具有相同的名字以及标签属于相同时序。时序的名字由 ASCII 字符,数字,下划线,以及冒号组成,它必须满足正则表达式 [a-zA-Z_:][a-zA-Z0-9_:]*, 其名字应该具有语义化,一般表示一个可以度量的指标,例如 http_requests_total, 可以表示 http 请求的总数。

时序的标签可以使 Prometheus 的数据更加丰富,能够区分具体不同的实例,例如 http_requests_total{method="POST"} 可以表示所有 http 中的 POST 请求。标签名称由 ASCII 字符,数字,以及下划线组成, 其中 __ 开头属于 Prometheus 保留,标签的值可以是任何 Unicode 字符,支持中文。

Prometheus常用的时序指标有以下4种

Ps.Prometheus客户端中提供4种指标类型,但是Prometheus的服务端并不区分指标类型,而是简单地把这些指标统一视为无类型的时间序列。

  • Counter: 计数器表示一种单调递增的指标,除非发生重置的情况下下只增不减,其样本值应该是不断增大的。适合用来表示服务的请求数、已完成的任务数、错误发生的次数等

  • Gauge: 仪表盘类型代表一种样本数据可以任意变化的指标,即可增可减。通常用于表示温度或者内存使用率这种指标数据。

  • Histogram:直方图主要用于表示一段时间范围内对数据进行采样,(通常是请求持续时间或响应大小),并能够对其指定区间以及总数进行统计。

    直接上图更好理解一点,histogram由一系列不同范围的bucket组成,代表落在不同范围里的数据有多少(累计直方图),还有sum(总响应时间)和count(总次数)

image.png

  • Summary:Summary 和 Histogram 类似,但Summary类型是在客户端直接聚合生成的百分位数

image.png 中位数(quantile=0.5)inerval长度为15.000115,全部数据耗时178380.0282111002s,一共有11892条数据

Histogram能利用histogram_quantile函数计算百分位数但精度受分桶影响很大,分桶少的话会使百分位数计算很不准确,而分桶多的话会使数据量成倍增加。Summary则是依靠原始数据计算出的百分位数,是很准确的值。但summary无法聚合,所以一般不怎么使用。

Prometheus使用

Prometheus的使用也较为简单

首先使用Docker部署一个Prometheus服务

1、本地创建 prometheus.yml

配置文件主要分为四个模块,这里只配置了数据源,到localhost:8000端口(宿主机)拉取数据。 9090服务器本身的一些数据。

global:  全局配置(如果有内部单独设定,会覆盖这个参数)
alerting: 告警插件定义。这里会设定alertmanager这个报警插件。
rule_files: 告警规则。 按照设定参数进行扫描加载,用于自定义报警规则,其报警媒介和route路由由alertmanager插件实现。
scrape_configs:采集配置。配置数据源,包含分组job_name以及具体target。又分为静态配置和服务发现

# my global confi
global:
  scrape_interval:     15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
# scrape_timeout is set to the global default (10s).

# Alertmanager configuration
alerting:
  alertmanagers:
  - static_configs:
    - targets:
      # - alertmanager:9093

# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
  # - "first_rules.yml"
  # - "second_rules.yml"

# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
  # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
  - job_name: 'prometheus'

  # metrics_path defaults to '/metrics'
  # scheme defaults to 'http'.

    static_configs:
    - targets: ['localhost:9090']

  - job_name: 'client'
    static_configs:
    - targets: ['host.docker.internal:8000']

docker使用起来确实方便,但是每次都会因为网络的问题卡半天,需要下来好好学习一下了。

一开始client配置的localhost:8000,然后代码上报数据放在宿主机,prometheus一直访问不到上报的数据,提示dial 127.0.0.1:8000被拒绝。

后面调了半天,把域名改成host.docker.internal才能获取到宿主机的数据。原因是docker内部和宿主机网络是隔离的,localhost是容器自己的网络。

2、拉取官方最新的prometheus镜像并使用我们写好的配置启动

docker run --name prometheus  --restart=always -d -p 9090:9090 -p 8000:8000 \
-v /Users/zhifeng.wei/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml \
prom/prometheus:latest --config.file=/etc/prometheus/prometheus.yml 

这里把prometheus的配置文件映射到了本地的配置文件(上面配置的yml),需要改成你的文件路径

此时访问localhost可以访问到prometheus server的网站了,第一个数据源是我们配置的localhost:9090/metrics,第二个数据源是localhost:8000,后面我们上报的数据可以上报到这里

image.png 3、Go实现数据上报

这里实际上就是实现了一个exporter,prometheus会定时来8000端口拉取数据,exporter的handler会负责提供数据

import(

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

)
func main(){
    // new一个counter,包含有taskName,status,errCode,msg等标签
    opsProcessed := promauto.NewCounterVec(
       prometheus.CounterOpts{
          Name: "test_ops_total",
          Help: "The total number of processed events",
       },
       []string{"taskName", "status", "errCode", "msg"},
    ) 
    // 注册指标,不使用默认的注册器
    reg := prometheus.NewRegistry()
    reg.MustRegister(opsProcessed)

    go func() {
       for {
          fmt.Println("report")
          opsProcessed.WithLabelValues("opsProcessed_task", "success", "1", "test").Inc()
          time.Sleep(2 * time.Second)
       }
    }()
    // 访问/metric会触发handler获得数据
    http.Handle("/metrics", promhttp.Handler())
    http.ListenAndServe("localhost:8000", nil)
}

运行程序,浏览器访问localhost:8000/metrics,可以看到上报的时序数据,重启会清除(如果不做持久化的话)

image.png

Grafana 简介

有了数据之后,还是希望可以用更好的方式可视化展示监控数据,这时候就需要Grafana了。

Grafana 是一个监控仪表系统,它是由 Grafana Labs 公司开源的的一个系统监测工具,它可以大大帮助我们简化监控的复杂度,我们只需要提供需要监控的数据,它就可以帮助生成各种可视化仪表,同时它还有报警功能,可以在系统出现问题时发出通知。

Grafana支持很多的数据源,包括我们前面说到的prometheus。

docker部署Grafana

我们使用doker-compose来一起部署prometheus和grafana docker-compose.yml

version: '2'

networks:
    monitor:
        driver: bridge

services:
    prometheus:
        image: prom/prometheus
        container_name: prometheus
        hostname: prometheus
        restart: always
        volumes:
            - ./prometheus.yml:/etc/prometheus/prometheus.yml
        ports:
            - "9090:9090"
            - "8000:8000"
        networks:
            - monitor

    grafana:
        image: grafana/grafana
        container_name: grafana
        hostname: grafana
        restart: always
        ports:
            - "3000:3000"
        networks:
            - monitor

启动服务

docker-compose up -d

现在prometheus启动在9090端口,grafana启动在3000端口

grafana的默认用户密码是admin/admin

然后设置数据源prometheus

image.png

image.png

image.png 配置好数据源后可以配置仪表盘

image.png 根据自己需要配置监控数据,这里监控的是test_ops_total这个指标过去1min的增量。

系统指标 这里有系统默认上报的一些指标的含义

常用函数

监控图可以使用PromQL的一些函数对时序数据进行处理,下面介绍一些常用的函数。 参考资料

rate,irate函数: rate(v range-vector) 函数可以直接计算区间向量 v 在时间窗口内平均每秒增长速率

irate(v range-vector) 函数用于计算区间向量的增长率,但是其反应出的是瞬时增长率。

它们的计算方法有所不同:irate取的是在指定时间范围内的最后两个数据点来算速率,而rate会取指定时间范围内所有数据点,算出一组速率,然后取平均值作为结果。 两者的作用类似,使用rate函数计算的是样本的平均增长速率,容易陷入“长尾问题”当中,其无法反应在时间窗口内样本数据的突发变化。 例如,对于主机而言在2分钟的时间窗口内,可能在某一个由于访问量或者其它问题导致CPU占用100%的情况,但是通过计算在时间窗口内的平均增长率却无法反应出该问题。 irate 反应出的是瞬时增长,能用于绘制快速变化的计数器,但是在长期趋势分析或者告警中更推荐使用 rate 函数。

rate(http_requests_total[5m])

increase: increase(v range-vector),参数v是一个区间向量,increase函数获取区间向量中的第一个后最后一个样本并返回其增长量。因此,可以通过以下表达式Counter类型指标的增长数量(时间序列每2min内的增长量)

 increase(node_cpu[2m])

histogram_quantile: histogram_quantile(φ float, b instant-vector)函数可以进行计算Histogram的分位数,其中φ(0<φ<1)表示需要计算的分位数。

下面统计的95%分位置的数目,需要注意的是通过histogram_quantile计算的分位数,并非为精确值

histogram_quantile(0.95, http_request_duration_seconds_bucket)

QA

1、前面配置的prometheus配置中,容器访问宿主机网络是通过host.docker.internal,但这种方式只能在mac和window使用,不适合用在生产环境

解决方法: Docker启动的时候会在主机上自动创建一个docker0网络,实际上是一个Linux网桥

ip addr show docker0

将host.docker.internal更换成这个网桥ip即可访问宿主机 image.png

2、使用gin框架上报的话,不需要像上面一样使用

http.Handle("/metrics", promhttp.Handler())
http.ListenAndServe("localhost:8000", nil)

可以直接使用gin进行上报,prometheus服务配置文件改成对应端口即可

s.GET("metrics", gin.WrapH(promhttp.Handler()))

3、linux 进入容器的命令 docker exec -it 容器id sh