grafana 和 Prometheus 采集数据并展示

2023-10-15  本文已影响0人  天空蓝雨

参考: 使用 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 展示一些数据

总体特征

可以看出来, 普罗米就是通过 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']

指标类型

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)
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_quantile(0.99, http_request_histogram_bucket)
Histogram 根据设置的采集数据的区间进行分类计数
from prometheus_client import Summary
s = Summary('request_latency_seconds', 'Description of summary')
s.observe(4.7)    # Observe 4.7 (seconds in this case)
采集的数据,从小到大排列,显示设置的 % 名次的数值

服务接入普罗米

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 前端

普罗米修斯告警

可以把告警发给 alertmanage 做进一步处理
告警内容:
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.yml  也有这个配置文件
./alertmanager  启动
alerting:
  alertmanagers:
    - static_configs:
        - targets: ['localhost:9093']

一些问题

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从而实现基于标签快速对时间序列进行过滤。

效果展示 各种监控都有对应的开源的 exporter
上一篇 下一篇

猜你喜欢

热点阅读