grafana 和 Prometheus 采集数据并展示

参考: 使用 Prometheus 监控服务器性能

进程监控:Prometheus+Process exporter+Grafana进程监控
容器监控 cadvisor + Prometheus+Grafana监控Docker容器

(cadvisor 指标比较多,我们在Grafana自己编辑采集的指标, 比如容器内存用这个container_memory_working_set_bytes{job="cadvisor", name="apc_boolean"}
默认的内存可能不是我们想要的,看到这个 https://blog.csdn.net/u010918487/article/details/106190764才知道的
)

主机监控 node_exporter Prometheus+Grafana 监控主机
prometheus client_golang 简单使用

Go进阶31:python 的 Prometheus Client教程
apc_boolean
gitbook 介绍普罗米的:
https://yunlzheng.gitbook.io/prometheus-book/introduction

接下来就详细介绍一下 普罗米的使用,并在最后的一个项目中使它结合 grafna 展示一些数据

总体特征

  • 收集的数据是时间戳 和 可选的标签 值 以及指标 共同存储
  • PromQL 自己的查询数据的 语言 类似 sql 这些
  • 采集数据通过http pull
  • 可以配置中间网关 push 数据,但最后 普罗米从网关 pull 数据
  • 支持服务发现获取 pull 地址(当然也可以直接配置 目标机器)
  • 支持 grafana 等仪表盘获取数据展示

可以看出来, 普罗米就是通过 http 采集数据, 并存储,数据展示可以被其他开源组件。

使用

  • 安装
    下载对应的版本
tar xvfz prometheus-*.tar.gz
cd prometheus-*
// 启动
./prometheus --config.file=prometheus.yml
// 可以编辑 prometheus.yml ,在里面配置一些数据采集的地址

配置文件有 global、rule_files和scrape_configs 三个字段

// 全局配置
global:
  scrape_interval:     15s   // 采集周期
  evaluation_interval: 15s  // 判断规则时间, 生成警报

rule_files:  // 加载其他规则文件
  # - "first.rules"
  # - "second.rules"

scrape_configs:   // 监控数据来源
  - job_name: prometheus
    static_configs:
      - targets: ['localhost:9090']

指标类型

  • Counter
    单调递增的计数器, 记录比如 请求总数,任务总数这些只会增加的指标, 对于波动的数据使用 Gauge
    python 实例:
pip install prometheus_client
进程重新启动时重置
from prometheus_client import Counter
c = Counter('my_failures', 'Description of counter')
c.inc()     # Increment by 1
c.inc(1.6)  # Increment by given value
表示服务启动后的数据增长, 可以用 rate (irate 波动更大)计算 增长速率 (模拟qps)
  • Gauge
    记录波动的数值, 比如请求的 qps(直接客户端上报,记得天一就是在入口处计算的qps, 直接是原子累加,不用在前端计算了), 温度变化等
    python:
from prometheus_client import Gauge
g = Gauge('my_inprogress_requests', 'Description of gauge')
g.inc()      # 增加
g.dec(10)    # 减少
g.set(4.2)   # 设置到某个值 

天一统计 qps:
就是一个在接口入口原子计数累积,每秒清零,其实可以把这个 qps 上报到 Gauge, 但是采集速度不是每秒的,所以还是有误差的

go func(t *time.Ticker) {
        defer ticker.Stop()
        for {
            // 一秒打印一次统计数量
            <- t.C
            common.GetLogger().Error("module current qps is:",  atomic.LoadInt64(&Model_rate))
                    httpRequestGauge.WithLabelValues("qps").Set(float64(atomic.LoadInt64(&Model_rate)))
            // 清空
            atomic.StoreInt64(&Model_rate, 0)
        }
    }(ticker)

效果:
为了便于观察, 把 label 的path 参数都改成 qps


上报的 qps 更为精确, rate 计算的斜率,由于是一段时间(时间改小点,更精确)的平均值,所以变化缓和一点
  • Histogram
    直方图, 对观察结果进行采样, 通常是 请求响应时间或响应大小,就是你只管 Observe, 其他的由普罗米抽样显示。并不是全部显示,因为全部展示数据量太大。
    我们也可以使用函数,查看 tp99 这些数据, 结果和 summary 计算的基本一致
histogram_quantile(0.99, http_request_histogram_bucket)
Histogram 根据设置的采集数据的区间进行分类计数
  • Summary
    同直方图
from prometheus_client import Summary
s = Summary('request_latency_seconds', 'Description of summary')
s.observe(4.7)    # Observe 4.7 (seconds in this case)
采集的数据,从小到大排列,显示设置的 % 名次的数值

服务接入普罗米

  • 查看服务监听正不正常
    http://localhost:9090/targets
    看到如果监听服务没有启动, 服务状态就是 down

    go 客户端代码, 模拟某个服务,并定时请 /test 接口
    我们定义了一个总请求量和每次请求的耗时 这两个指标
package main

import (
    "fmt"
    "github.com/prometheus/client_golang/prometheus"
    "github.com/prometheus/client_golang/prometheus/promhttp"
    "log"
    "math/rand"
    "net/http"
    "strconv"
    "time"
)

// prometheus.NewCounterVec  带 Vec的可以多添加 label 参数


// 创建计数器
var httpRequestCount = prometheus.NewCounterVec(
    prometheus.CounterOpts{
        Name: "http_request_count",
        Help: "http request count",
    },
    []string{"endpoint"},
)


// 创建Gauge
var httpRequestGauge = prometheus.NewGaugeVec(
    prometheus.GaugeOpts{
        Name: "http_request_Gauge",
        Help: "http request Gauge",
    },
    []string{"endpoint"},
)



// 创建 summary 指标
var httpRequestSummary= prometheus.NewSummaryVec(
    prometheus.SummaryOpts{  // 指标名称
        Name: "http_request_summary",
        Help: "http request Summary",
        // 客户端计算 百分比分类, 不加这个配置就没数据
        // 后面的 0.05 0.01 代表 百分比误差, 0.5 对应的是 0.05 表示 45% - 55% 的区间都可以作为目标值
        // 假设某个0.5-quantile的值为120,由于设置的误差为0.05,所以120代表的真实quantile是(0.45, 0.55)范围内的某个值。
        // 参考: https://cloud.tencent.com/developer/news/319419
        Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}, // 返回五分数, 九分数, 九九分数
    },
    []string{"endpoint"},  // label 列表
)


// 创建 Histogram 指标  (也可以使用  histogram_quantile(0.99, http_request_histogram_bucket) 来计算 tp99)
var httpRequestHistogram = prometheus.NewHistogramVec(
    prometheus.HistogramOpts{  // 指标名称
        Name: "http_request_histogram",
        Help: "http request Histogram",
        Buckets: prometheus.LinearBuckets(20, 20, 5), //第一个桶20起,每个桶间隔20,共5个桶。 所以20, 40, 60, 80, 100
    },
    []string{"endpoint"},  // label 列表
)





// 初始化, 注册两个指标
func init() {
    // 请求总数,可计算 用rate 函数计算 qps, 或者计算 label 为枚举类型的百分比, 直接算就好了
    prometheus.MustRegister(httpRequestCount)
    // cpu 使用率这些,直接上传 qps
    prometheus.MustRegister(httpRequestGauge)
    // Summary 可以分析平均耗时 (客户端计算,不确定的状态分布,可以写几个范围)
    prometheus.MustRegister(httpRequestSummary)
    // 直方图, 也可以分析平均耗时 (服务端计算)
    prometheus.MustRegister(httpRequestHistogram)

}


func main() {
    // metrics 接口,用于收集指标
    http.Handle("/metrics", promhttp.Handler())
    // 自测接口, 用于修改指标
    http.HandleFunc("/test0", handler)
    http.HandleFunc("/test1", handler)
    go func() {
        fmt.Println("服务启动")
        err := http.ListenAndServe(":8888", nil)
        if err != nil{
            fmt.Println(err)
        }
    }()
    startClient()
    doneChan := make(chan struct{})
    <-doneChan
}



// 自定义接口
func handler(w http.ResponseWriter, r *http.Request) {
    start := time.Now()
    path := r.URL.Path
    // 请求计数器, 请求路径为标签
    httpRequestCount.WithLabelValues(path).Inc()
    // 模拟处理不同的耗时
    n := rand.Intn(100)
    if n >= 95 {  // 5% 耗时 100
        time.Sleep(100 * time.Millisecond)
    } else { // %95 耗时 50
        time.Sleep(50 * time.Millisecond)
    }
    // 请求耗时 xx ms
    elapsed := (float64)(time.Since(start) / time.Millisecond)
    // 记录当前请求的耗时 Summary
    httpRequestSummary.WithLabelValues(path).Observe(elapsed)
    // 记录平均耗时 直方图
    httpRequestHistogram.WithLabelValues(path).Observe(elapsed)
    httpRequestGauge.WithLabelValues(path).Set(float64(rand.Intn(100)))
}

// 测试脚本
func startClient() {
    sleepTime := 1000
    // 模拟请求频率,每三十秒请求间隔设置 1s, 每两分钟设置为 0.2, 就是 0.2 高频会持续不超过 30秒
    go func() {
        ticker := time.NewTicker(2 * time.Minute)
        for {
            <-ticker.C
            sleepTime = 200
            <-time.After(30 * time.Second)
            sleepTime = 1000
        }
    }()

    for i := 0; i < 100; i++ {
        go func() {
            for {
                sendRequest()
                time.Sleep((time.Duration)(sleepTime) * time.Millisecond)
            }
        }()
    }
}

func sendRequest() {
    api_verson := strconv.Itoa(rand.Intn(2))
    resp, err := http.Get("http://localhost:8888/test" + api_verson)
    if err != nil {
        log.Println(err)
        return
    }
    resp.Body.Close()
}

搜索我们的指标名称, 可以加 label 作为过滤条件
点击 graph 可以看到 请求总数的变化曲线

查看qps 可以使用 自带函数 rate


30s 为计算qps的单个区间, 同样支持 标签过滤

参考: https://cjting.me/2017/03/12/use-prometheus-to-monitor-server/
怎么计算 qps, 和请求耗时, 并对接 grafana

普罗米修斯对接 grafana 前端

  • 新建数据源为 普罗米,然后配置请求数据 url


    安装grafana 后登陆,配置data source 为 普罗米修斯
  • 新建一个 dashborad, 用来展示数据


    我们直接输入 普罗米的查询语句,然后点执行就可以了
  • 展示的数据是根据label 分类展示的


    可以看到展示数据是按照label 展示的,如果不过率的话,就展示所有 label

    当然也可以在一个 dashbroad 展示几个 查询语句,但是建议只展示同一个 指标类型,不然坐标轴不统一

  • 保存dashboad


    编辑之后,需要点保存,不然刷新修改的东西就没了
  • 四种数据类型效果
    可以拖动 panel, 摆放合适的位置, 想要看具体的某个 label 数据,直接点击 tag 就好了。


    我们建立了 几个panel, 用来展示不同的数据

普罗米修斯告警

可以把告警发给 alertmanage 做进一步处理

告警内容:

  • 告警名称:用户需要为告警规则命名,当然对于命名而言,需要能够直接表达出该告警的主要内容
  • 告警规则:告警规则实际上主要由 PromQL 进行定义,其实际意义是当表达式(PromQL)查询结果持续多长时间(During)后出发告警
  • 模板变量
    通过labels.<labelname>变量可以访问当前告警实例中指定标签(就是告警里面 label 那些健值对)的值。value则可以获取当前PromQL表达式计算的样本值(就是判断是不是告警的值)
    比如:
annotations:
      summary: "Instance {{ $labels.instance }} down"
      description: "{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 5 minutes."
  • 设置告警规则
rule_files:
  - /etc/prometheus/rules/*.rules

我们可以设置多个告警文件, 普罗米会默认一分钟(通过 evaluation_interval 设置)跑所以的告警语句

  • 告警状态

样本值为1表示当前告警处于活动状态(pending 就是触发了,但是可能设置持续一分钟才告警,所以为等待状态 或者firing 已经发出告警了),当告警从活动状态转换为非活动状态时,样本值则为0。

  • Alertmanager 接受普罗米的告警
    从普罗米官网 下载 alertmanage 或 docker 安装。
// alertmanager.yml  也有这个配置文件
./alertmanager  启动
  • 关联Prometheus与Alertmanager
alerting:
  alertmanagers:
    - static_configs:
        - targets: ['localhost:9093']
  • Alertmanager配置概述
    略 就是配置一些邮件这些。实际操作的时候在写

一些问题

  • 如何将日志输入?
    简短的回答:不要!改用ELK 堆栈 之类的东西
    更长的答案:Prometheus 是一个收集和处理指标的系统,而不是事件记录系统

  • 如何选择使用哪种数据格式呢
    先说几个简单的:
    qps 可以用 counter 结合rate/irate进行计算
    在线人数,或者服务状态, 温度变化用 Gauge

  • 关于 Summary 里面参数 Objectives 的设置
    参考 https://cloud.tencent.com/developer/news/319419

Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}, // 返回五分数, 九分数, 九九分数

主要是 0.5: 0.05 说明是 50% 的数据, 其实是 45% - 50% 中的一个数据, 并不能精确到 50% 整,因为数据太多,计算精确到话,太耗性能。关心的 0.99 可以计算准确一点。

https://www.mianshigee.com/tutorial/prometheus-book/grafana-templating.md
怎么导出自己编辑好的模板:

dashboard 导出
模板导入, 如果没有数据,要先手动配置数据源才行
添加变量

编辑变量

可以使用 label_values({job="$job"}, instance) 进行快速筛选某个属性

查询语句引用当前选择的变量值即可

比如上查询了 dfir_service_time_cost_count 这个指标, 所有job的可选值, 简单的正则分组匹配即可

dfir_service_time_cost_count{instance="91yxlv2.tianyi.iflytekauto.cn:80", job="ugc-0-gray", path="/ugc/run", service="UGC"}

或者使用指标里面的属性 自定义图例

如果把字符串拼接到字符串,请用 ${xx} 而不能直接 $xx

为啥用 “=~” 来指定变量呢,这是因为菜单 select 可以是多选,值会是 xx|xx|xx 的格式, ~ 是正则匹配,不加会匹配不到的

变量的值可以支持单选或者多选,当对接Prometheus时,Grafana会自动将$node的值格式化为如“host1|host2|host3”的形式。配合使用PromQL的标签正则匹配“=~”,通过动态改变PromQL从而实现基于标签快速对时间序列进行过滤。

效果展示
  • 关于如何监控主机 cpu 内存等
    node_exporter 用普罗米开源采集工具, 启动就好了
    https://cloud.tencent.com/developer/article/1808172

  • grafana 如何新建不同的用户以及设置他们对dashboard 的权限
    https://www.modb.pro/db/499351
    左下角从组织开始,新建组织,新建用户等,以及设置他们的角色 (每个组织默认会有当前的 admin 用户,并且就算 admin自己也删不掉是新建 组织的超级管理员)
    admin 用户可以管理所有的组织和所有的dashboard 以及 用户
    每个组织下可以有单独的管理员和可编辑权限和只读权限

    可以对每个dashboard 进行编辑,添加已经创建的用户或者组,以及对应的权限

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

推荐阅读更多精彩内容