prometheus+docker套件

2024-04-18 21:02:22 监控系统 69 0

环境搭建

参考地址 https://www.jianshu.com/p/bd64a114aab0

组成部分

成员 描述
prometheus 定时采集数据
node-exporter 所有可以向 Prometheus 提供监控样本数据的程序都可以称为 Exporter
grafana 展示各种采集的数据,包含且不限于
prometheus 数据源,还可以是 mysql 、elasticsearch等

docker-compose.yaml

注:对应挂载的目录,要赋予写入文件的权限

version: "3.7"
services:
#  node-exporter:
#    # 所有可以向 Prometheus 提供监控样本数据的程序都可以称为 Exporter
#    # Prometheus 官方的 Node Exporter 提供对 *NIX 系统、硬件信息的监控,监控指标包括 CPU 使用率/配置、系统平均负载、内存信息、网络状况、文件系统信息统计、磁盘使用情况统计等
#    # 具体见 https://github.com/prometheus/node_exporter
#    image: prom/node-exporter:latest
#    container_name: "node-exporter-app"
#    ports:
#      - "5110:9100"
#    restart: always
#    networks:
#      default:
#        ipv4_address: 172.31.0.2

  prometheus:
    image: prom/prometheus:latest
    container_name: "prometheus-app"
    restart: always
    ports:
      - "5111:9090"
    volumes:
      - "./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml"
      - "./prometheus/data:/prometheus"
    networks:
      default:
        ipv4_address: 172.31.0.3

  grafana:
    image: grafana/grafana
    container_name: "grafana-app"
    ports:
      - "5112:3000" # 初始的账号/密码   admin/admin
    restart: always
    volumes:
      - "./grafana/data:/var/lib/grafana"
      - "./grafana/grafana.ini:/etc/grafana/grafana.ini"
    networks:
      default:
        ipv4_address: 172.31.0.4

networks:
  default:
    external:
      name: network_prome

prometheus.yaml

global: # 全局配置,
  scrape_interval: 15s # 默认抓取周期
  external_labels:
    monitor: 'codelab-monitor'
scrape_configs:
  - job_name: 'search_gateway' # 设定的抓取任务名称,比如,对应微服务的节点名字
    scrape_interval: 15s # 每过指定时长,尝试一次抓取
    scrape_timeout: 10s # 每次抓取的超时时间,不能超过 scrape_interval 设定的时间
    metrics_path: /metrics  #获取指标的路由地址,配合下方 targets 自动拼接最终目标地址。例如 172.30.16.1:2333/metrics
    static_configs:
      - targets: [172.30.16.1:2333] # 这个为监听指定服务服务的ip和port,需要修改为自己的ip,不能使用localhost和127.0.0.1,具体看看本机与容器的虚拟IP

grafana.ini

我这里以QQ邮箱,作为邮件告警途径,示例配置 如果你不计划用邮箱告警,可以暂时忽略该文件

#################################### SMTP - POP3配置 ##########################
[smtp]
; 启用 smtp
enabled = true
; 邮件服务器地址和端口
host = smtp.qq.com:587
# 发送告警邮件 POP3 如果是QQ邮箱,则是QQ号
user = 1290336562
; 发送告警邮件邮箱 POP3 密码
password = TODO
; 发件邮箱 这个QQ下,可能有很多个邮箱,选其中的QQ邮箱地址就可以了
from_address = hlzblog@vip.qq.com
; 发件人名称
from_name = 云天河Blog

Makefile

自动化部署脚本

all: run

run:
    @# 删除镜像
    @make -s down
    @# 以后台挂起的模式运行
    @docker-compose  --compatibility -p prome_local  up -d

down:
    @docker-compose  -p prome_local down

stop:
    @docker-compose  -p prome_local stop

start:
    @docker-compose  -p prome_local start

restart:
    @docker-compose  -p prome_local restart

cnet:
    @# 创建网卡
    @docker network create --subnet=172.31.0.0/16 network_prome

ini:
    @clear
    @#mkdir -p /data/www
    @make -is cnet
    @make -s run

clear:
    @clear
    @make -s down
    @docker rmi network_prome

in:
    @docker exec -it prometheus-app bash

log:
    @docker logs -f prometheus-app

用Prometheus配置Grafana

添加数据源

第1步:主界面左下角 image.png 第二步:点击添加数据源 image.png 第三步:填写普罗米修斯的服务地址,用刚刚docker-compose中的IP即可,无需考虑容器IP image.png 注:Exemplars 这里可以不用配置 配置主动拉取数据的地址【后文主要介绍拉模式】 如果是golang语言 可以用包 https://github.com/armon/go-metrics 结合gin开个路由打点

导入看板

image.png

官方模板

https://grafana.com/grafana/dashboards/?search=golang 推荐ID: consul管理 8919、 主机基础信息 9276、 golangSDK自带指标 10826 image.png 绑定数据源,然后导入 image.png

新增看板

image.png

image.png

示例一个Panel的配置,kafka的生产、消费指标。

我们方便演示,我们新建了一个主看板,然后做以下操作 Step 1 增加看板变量 因为我们发消息、生产消息的服务不同 为了方便我们区分不同的抓取任务【这里可以试不同服务名】 我们可以先给 主看板 增加环境变量,点击我们的看板右上角设置按钮 image.png image.png image.png 我们保存后,回到 主看板,就会发现多了个选项了 image.png Step 2 配置kafka 子看板 我们依旧,右上角,点击按钮,添加子看板 image.png 然后出现下面界面,点击圈圈内容 image.png 选择我们刚刚配置好的数据源 image.png image.png

请记得修改 datasource 里的配置,示例如下. 用 PromSQL , 汇总

  • 每1分钟为时间间隔的打点数据
  • 以Topic这个label分组
  • 计算能平滑展示 Kafka 每秒消费速率
  • 只看指定scrape_configs中的某个job_name的统计结果
    sum(rate(kafka_consumer{job="$application"}[1m]) )  by (topic)

然后就能看到图表了 image.png 当然我们一个统计里面,可以组合多种指标,比如我们现在再增加一个指标 image.png 让他们在一个子看板里进行展示 image.png

采集类型

promethus采集

主动采集:通过指定API 定时 去业务服务方拉取 ---下文以此模式讲解为主 具体方式可以参考 https://blog.51cto.com/u_14065119/category3

被动采集:业务服务方主动推送到 promethus

数据类型

Counter 表示收集的数据是按照某个趋势(增加/减少)一直变化的 常用场景: 1 记录http或者rpc一段时间内的请求总量 2 记录Kafka一段时间内发送到某个Topic的数量; 3 记录Kafka一段时间内,从某个Topic消费消息的次数。

Gauge 表示搜集的数据是一个瞬时的值,与时间没有关系,可以任意变高变低。 常用场景: 1 记录 内存 使用率 2 记录 CPU 使用率 3 记录 磁盘 使用率等

Histogram 会依据配置指标的 len 范围形成 有序的几个分桶,响应数值的指标将会命中不同 len 的分组 常用场景: 通常它采集的数据展示为直方图【因为分桶计数】 优势:可以减少打点记录的数量 缺点:要提前知道数据的大致分布范围 注意:设计桶的时候:数据分布较密处桶间隔制定的较窄一些,分布稀疏处可制定的较宽一些 1 P99、P95、P90 指标 比如HTTP响应时间指标分布 50ms 100ms 200ms 300ms 500ms 1000ms 3000ms

先配置指标

    var httpMsMetrics = prometheus.NewHistogramVec(prometheus.HistogramOpts{
        Namespace: "http", // 命名空间
        Subsystem: "",
        Name:      "response_ms", // 指标名称
        Help:      "响应时间,毫秒",
        Buckets:   []float64{10, 25, 50, 100, 150, 200, 300, 500, 1000, 3000},
    }, []string{"method", "path"}) // 指标标签

再注册指标,指标才会在http开发的prometheus路由上暴露指标 注:这一步一定要在我们服务启动前,初始化好

prometheus.MustRegister(httpMsMetrics)

示例,在运行的服务中,记录一个指标。这里模拟请求了1000次,最低的 50 毫秒

    for i := 0; i < 1000; i++ {
        var f = float64(i + 50)
        go func() {
            <-time.After(2 * time.Second)
            httpMsMetrics.WithLabelValues("GET","comic/detail_by_id").Observe(f)
        }()
    }

然后在grafana上配置,展示指标=命名空间_指标名称。

histogram_quantile(0.95, sum(rate(http_response_ms_bucket{job="$application"}[5m])) by (le, method, path))

注:这里的 le 是 NewHistogramVec 这种指标,在分桶的时候,自定义的标签名

展示指标的计算逻辑 比如目前命中桶的分布情况是

范围(ms) 数量
0~50 23
50~100 761
100~200 4536
200~300 351
后面的范围都省略 后面的当成是0

P90的含义是汇总桶的总数,从小到大排序,第90%个数据所在的位置就认定为P90的结果 比如这里第90%个数是第 5104 个数,在 100~200ms的范围。 它处于这个桶的第 5104 - 23 -761 = 4320 个数。 按桶的区间算,他的位置所处毫秒位置=开始位置 100 加上 (200 -100) * (4320 / 4536) = 195.23 ms

可以注意到因为是基于线性分布的假设,不是准确的数据。比如假设 300-500 的桶中耗时最高的请求也只有 310ms, 得到的计算结果也会是 400ms. 桶的区间越大,越不准确,桶的区间越小,越准确。

Summary 和 Histogram 类似,由 {quantile="<φ>"}, sum, count 组成,主要用于表示一段时间内数据采样结果(通常是请求持续时间或响应大小),但它直接存储了 quantile 数据,而不是根据统计区间计算出来的 注:这个日常没用到过,可以忽略

存储原理

采用TSDB 时序数据库 更多原理见译文 从头编写一款时间序列数据库 优势:存储64位的浮点数,基于时序相关压缩算法,每一个样本大概占用 1-2 字节大小(1.7Byte)【总之磁盘省空间】 其存储的二维表达大致如下。 注意:要记得设置数据存储的过期时间哟,不然太占磁盘了! image.png 横坐标 是时间序列【逐渐递增】;纵坐标 是具体指标 image.png

  • Prometheus 的内存消耗主要是因为每隔 2 小时做一个 Block 数据落盘,落盘之前所有数据都在内存里面,因此和采集量有关。
  • 加载历史数据时,是从磁盘到内存的,查询范围越大,内存越大。这里面有一定的优化空间。
  • 一些不合理的查询条件也会加大内存,如 Group 或大范围 Rate。

Write TSDB是构建在HBase之上的时序数据库,HBase是一个KV宽表存储系统,因此OpenTSDB的存储机制是围绕HBase的KV宽表模型展开的 示例,一个时序指标存储 K/V image.png 数据采集后,同时在内存和 WAL 保存数据 WAL: 相当于临时日志,可以在 prometheus 重启的时候,把临时数据重新载入内存 然后 每2个小时 进行落盘,每次落盘会写入到 1个 存储块中,然后清除内存与 WAL 中对应数据

每个目标暴露成百上千个不同的时间序列,写入模式是完全垂直和高度并发的 因为来自每个目标的样本是独立的 理论上一个服务的 series数量不会超过10000个 不然在 prometheus 定时主动采集的时候可能会超时,因为每2个小时才刷盘内存也会有压力

Query 倒排索引+正向索引 倒排:基于Label建立倒排 正排:将 SeriesId 的值,在建立倒排的时候,以ID从小到大排序

Label SeriesId
app="ops" 1,13,64,312
env="dev" 2,13,66,231,261
env="prd" 123,145,311,312,2383,5656
name="request_total" 3,145,346,2341
...

为什么这么处理呢,示例一个场景:我要查询满足多个指标的数据 如 app="ops" 而且 满足 env="prd"的数据。 如果不使用正排,则会有O(n)的指标数的指数级聚合复杂度,如这里O(N^2) 如果使用正排,则可以减少扫描量,则第一次只用扫描 1~312,第二次扫描123~312 一般情况下,指标越多,效果会越明显 剩下就是维护这个索引,通过维护时间线与ID、标签与倒排表的映射关系,可以保证查询的高效率

查询语句

promSQL 见官方文档 https://prometheus.io/docs/prometheus/latest/querying/basics/ 函数使用文档 https://prometheus.io/docs/prometheus/latest/querying/functions/ 一般来说,函数是给单个指标用来计算的,多个指标尽量不要放在一个函数里面 :在我们查询1个星期的数据时,就会把这1星期涉及的块,对应数据载入内存,所以拉数据也要悠着点

示例配置Topic消费 示例含义: image.png

以下参考 https://jishuin.proginn.com/p/763bfbd6859c rate 它以可预测的每秒输出单位产生平滑的rate 如 rate(http_requests_total[5m]) 得出的是HTTP在5分钟窗口内,平均每秒的请求率。 irate 计算每秒的增长率,但只对规定采样周期内的最后两个样本进行计算,而忽略前面所有样本可以避免在时间窗口范围内的长尾问题 两者算法实现: 详见 https://blog.csdn.net/u010961631/article/details/105658516 相同:要取一定的时间间隔作为计算依据 区别:在要看时间间隔短【2分钟以内】的采样场景,irate 看起来起伏比较大 rate 容易表现为平整 image.png 超过2分钟,区别不大 image.png 有了变化率,我们想看变化量,在外面包一层sum函数就可以了 比如 sum(irate(http_requests_total[1m]) ) 得出的是HTTP在1分钟窗口内,平均每秒请求量(QPS)。 关于更多函数的使用,请看官方对应章节
https://prometheus.io/docs/prometheus/latest/querying/functions/

查1分钟内的请求总数 最佳方案

sum(http_request_total{job="$application", path!="/metrics"} - (http_request_total{job="$application", path!="/metrics"} offset 1m) ) by (method,path)

为什么没使用 increase 因为在量小的时候数据不够精准。比如,前1分钟,对应节点没有参考值,则本次对应节点的值为0,如果用在量小的场景,如,订单数等于0就告警,就可能误报

sum(increase(http_request_total{job="$application", path!="/metrics"}[1m])) by (method,path)

查询每分钟内的缓存命中率

increase(cache_hit_total{job="$application"}[1m])  / (
    increase(cache_hit_total{job="$application"}[1m])  + increase(cache_miss_total{job="$application"}[1m]) 
) * 100

避坑指南

Rate Counter 类型主要是为了 Rate 而存在的,即计算速率,单纯的 Counter 计数意义不大,因为 Counter 一旦重置,总计数就没有意义了 风险:有可能抓取时,网络抖动、抓取速度缓慢、发代码等,导致数据丢失或者最终抓到数据的时间不平滑,所以 Rate 值很少是精确的 建议:将 Rate 计算的范围向量的时间至少设为抓取间隔的四倍 原因:这将确保即使抓取速度缓慢,且发生了一次抓取故障,你也始终可以使用两个样本【两个点才能成线,算趋势】 实践:例如,对于 15s 的抓取间隔,可以使用 1 分钟的 Rate 计算 如果 Rate 的时间区间内有数据缺失,它会基于趋势进行推测,比如:

关于函数除法计算时,遇到分母为0出现NAN 把0的情况排除即可 处理前

rate({__name__="hystrix_command_latency_total_seconds_sum"}[60s])
/
rate({__name__="hystrix_command_latency_total_seconds_count"}[60s])

处理后

rate({__name__="hystrix_command_latency_total_seconds_sum"}[60s])
/
(rate({__name__="hystrix_command_latency_total_seconds_count"}[60s]) > 0)

Increase函数的坑 如果一个时间序列之前不存在然后以值1出现,那么这时候 Prometheus 就不知道计数器是实际上是增加还是第一次被简单抓取到。那么increase()在处理的时候就直接返回0 了

sum(increase(http_request_total{job="$application", path!="/metrics"}))  by (method,path)

image.png 要解决这个问题,直接 offset 相减即可

sum(http_request_total{job="$application", path!="/metrics"} - (http_request_total{job="$application", path!="/metrics"} offset 1m) ) by (method,path)

注:因为 Counter 类型的数据,每隔一定时间有可能会被重置,所以相减后,数据值可能为负数,这时候我们丢弃这样的值就行了

mysql采集

自己用代码定时跑指标数据,存储到 mysql 表里,或者直接用现成业务数据进行统计 根据前文,记得先添加 mysql 数据源 image.png

示例配置Panel

功能:查看游客浏览记录数据 image.png 示例 SQL 如下,其中 time_div变量,是当前看板配置的变量,枚举值,如,1h,3h,6h,1d,7d

SELECT
  $__timeGroupAlias(created_at, $time_div),
  count(*) AS "次数"
FROM visitor_foot_mark_analysis
WHERE
  $__timeFilter(created_at)
GROUP BY 1
ORDER BY $__timeGroup(created_at, $time_div)

配置好后,我们可以尝试选择时间范围,查看效果 image.png 确认配置后,保存看板即可 我们最后再看看展示效果 image.png 如果界面感觉小,可以触碰下看板上的标题,点击View 就可以网页全屏,单独看这个看板了 image.png

告警配置

策略

生效的时间范围:业务监控,如,早上10点到晚上22点 告警接收人:按人员分组接收 通知频率设置、通知恢复等

途径

邮件

自带功能,直接配置即可
在本文开头部分,已经配置好邮件告警的信息 剩下的就是使用了

  • Step 1 通知渠道列表

image.png

  • Step 2 点击创建通知渠道

image.png

  • Step 3 配置、测试、并保存配置

描述:哪些人以哪种方式,接收告警 image.png

  • Step 4 配置告警渠道

描述:什么场景,去让Step 3 中的那些人,去接收报警 image.png image.png image.png

  • Step 5 实战

现在随便找个时序相关监控,点击编辑 image.png 创建告警策略 image.png 配置告警触发条件,示例, 设置1分钟内,漫画章节详情接口的请求量超过100次,就触发告警 image.png 刚刚配置了2个指标 A 是监控指标 B是告警指标 image.png 补充说明: Evaluate every表示打点频率,上图中表示,每1分钟打点一次。 如果触发了告警,会变成 Pending状态 image.png 如果告警,持续超过5分钟,就会触发告警策略 image.png 一般同步发邮件会有一定延迟,底层实现的时候,大多都是通过通知消息中间件,会有对应消费端,去实现逐步发送邮件的,所以在邮件接收上,可能会有一点延迟【常规是1分钟以内】,但对我们来说,是可以容忍的

记得右上角保存 image.png 接着我们就可以用 压测工具,比如这里我用 wrk工具,进行压测,尝试触发告警 image.png 考虑刚刚说的发邮件可能有点延迟,我们玩七八分钟手机,看看会不会有邮件发过来 触发下图,说明是成功了 image.png image.png 因为我们告警是每连续5分钟,就触发一次告警 所以如果一直在告警,则会固定时长通知一次 image.png

Webhook

一般需要开发,流程如图 image.png 现成 飞书 组件 https://github.com/XUJiahua/alertmanager-webhook-feishu 现成 钉钉 组件 https://github.com/sunnywalden/prometheus-webhook-dingding

告警指标

业务指标

更多可根据业务场景,自行给出 也可以用于简单的巡检 ...

SRE指标

网站可靠性工程师,应该合理选择黄金指标:延迟、流量、错误数、饱和度

指标名称 备注
MQ的生产、消费TPS;
缓存命中率;
系统性能各项指标; 实时带宽流量、CPU使用率、磁盘使用率等
应用内存、协程数等指标;
请求量、QPS、请求来源地区等常见指标;
HTTP状态码非200的相关指标
...
注:若无特殊说明,文章均为云天河原创,请尊重作者劳动成果,转载前请一定要注明出处