成员 | 描述 |
---|---|
prometheus | 定时采集数据 |
node-exporter | 所有可以向 Prometheus 提供监控样本数据的程序都可以称为 Exporter |
grafana | 展示各种采集的数据,包含且不限于 |
prometheus 数据源,还可以是 mysql 、elasticsearch等 |
注:对应挂载的目录,要赋予写入文件的权限
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
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
我这里以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
自动化部署脚本
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
第1步:主界面左下角 第二步:点击添加数据源 第三步:填写普罗米修斯的服务地址,用刚刚docker-compose中的IP即可,无需考虑容器IP 注:Exemplars 这里可以不用配置 配置主动拉取数据的地址【后文主要介绍拉模式】 如果是golang语言 可以用包 https://github.com/armon/go-metrics 结合gin开个路由打点
https://grafana.com/grafana/dashboards/?search=golang 推荐ID: consul管理 8919、 主机基础信息 9276、 golangSDK自带指标 10826 绑定数据源,然后导入
我们方便演示,我们新建了一个主看板
,然后做以下操作
Step 1 增加看板变量
因为我们发消息、生产消息的服务不同
为了方便我们区分不同的抓取任务【这里可以试不同服务名】
我们可以先给 主看板
增加环境变量,点击我们的看板右上角设置按钮
我们保存后,回到 主看板
,就会发现多了个选项了
Step 2 配置kafka 子看板
我们依旧,右上角,点击按钮,添加子看板
然后出现下面界面,点击圈圈内容
选择我们刚刚配置好的数据源
请记得修改 datasource
里的配置,示例如下.
用 PromSQL , 汇总
sum(rate(kafka_consumer{job="$application"}[1m]) ) by (topic)
然后就能看到图表了 当然我们一个统计里面,可以组合多种指标,比如我们现在再增加一个指标 让他们在一个子看板里进行展示
主动采集:通过指定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)【总之磁盘省空间】 其存储的二维表达大致如下。 注意:要记得设置数据存储的过期时间哟,不然太占磁盘了! 横坐标 是时间序列【逐渐递增】;纵坐标 是具体指标
Write
TSDB是构建在HBase之上的时序数据库,HBase是一个KV宽表存储系统,因此OpenTSDB的存储机制是围绕HBase的KV宽表模型展开的
示例,一个时序指标存储 K/V
数据采集后,同时在内存和 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消费 示例含义:
以下参考 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 容易表现为平整
超过2分钟,区别不大
有了变化率,我们想看变化量,在外面包一层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)
要解决这个问题,直接 offset 相减即可
sum(http_request_total{job="$application", path!="/metrics"} - (http_request_total{job="$application", path!="/metrics"} offset 1m) ) by (method,path)
注:因为 Counter
类型的数据,每隔一定时间有可能会被重置,所以相减后,数据值可能为负数,这时候我们丢弃这样的值就行了
自己用代码定时跑指标数据,存储到 mysql
表里,或者直接用现成业务数据进行统计
根据前文,记得先添加 mysql
数据源
功能:查看游客浏览记录数据
示例 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)
配置好后,我们可以尝试选择时间范围,查看效果 确认配置后,保存看板即可 我们最后再看看展示效果 如果界面感觉小,可以触碰下看板上的标题,点击View 就可以网页全屏,单独看这个看板了
生效的时间范围:业务监控,如,早上10点到晚上22点 告警接收人:按人员分组接收 通知频率设置、通知恢复等
自带功能,直接配置即可
在本文开头部分,已经配置好邮件告警的信息
剩下的就是使用了
描述:哪些人以哪种方式,接收告警
描述:什么场景,去让Step 3 中的那些人,去接收报警
现在随便找个时序相关监控,点击编辑
创建告警策略
配置告警触发条件,示例, 设置1分钟内,漫画章节详情接口的请求量超过100次,就触发告警
刚刚配置了2个指标 A 是监控指标 B是告警指标
补充说明:
Evaluate every
表示打点频率,上图中表示,每1分钟打点一次。
如果触发了告警,会变成 Pending
状态
如果告警,持续超过5分钟,就会触发告警策略
一般同步发邮件会有一定延迟,底层实现的时候,大多都是通过通知消息中间件,会有对应消费端,去实现逐步发送邮件的,所以在邮件接收上,可能会有一点延迟【常规是1分钟以内】,但对我们来说,是可以容忍的
记得右上角保存
接着我们就可以用 压测工具,比如这里我用 wrk
工具,进行压测,尝试触发告警
考虑刚刚说的发邮件可能有点延迟,我们玩七八分钟手机,看看会不会有邮件发过来
触发下图,说明是成功了
因为我们告警是每连续5分钟,就触发一次告警
所以如果一直在告警,则会固定时长通知一次
一般需要开发,流程如图
现成 飞书
组件 https://github.com/XUJiahua/alertmanager-webhook-feishu
现成 钉钉
组件 https://github.com/sunnywalden/prometheus-webhook-dingding
更多可根据业务场景,自行给出 也可以用于简单的巡检 ...
网站可靠性工程师,应该合理选择黄金指标:延迟、流量、错误数、饱和度
指标名称 | 备注 |
---|---|
MQ的生产、消费TPS; | |
缓存命中率; | |
系统性能各项指标; | 实时带宽流量、CPU使用率、磁盘使用率等 |
应用内存、协程数等指标; | |
请求量、QPS、请求来源地区等常见指标; | |
HTTP状态码非200的相关指标 | |
... |
评论列表点此评论