PromQL 使用
对一段指标的时间序列进行分析的语言(Prometheus 内置),它的核心是对指标的时间序列进行分析、计算和聚合,帮助用户从监控数据中提取有价值的信息
PromQL 是 Prometheus 监控系统内置的一种查询语言,PromQL 允许你以灵活的方式选择,聚合等其他方式转换和计算时间序列数据,该语言仅用于读取数据,可以说 PromQL 是我们学习 Prometheus 最困难也是最重要的部分,接下来我们将进入 PromQL 的基础知识,理论基础,然后深入了解更加高级的 PromQL 查询模式
当 Prometheus 从系统和服务收集指标数据时,它会把数据存储在内置的时序数据库中,要对收集到的数据进行任何处理,我们都可以使用 PromQL 从 TSDB 中读取数据,同时可以对所选的数据进行过滤,聚合以及其他转换操作
PromQL 执行可通过两种方式触发:
- 在 Prometheus 服务器中,记录规则和报警规则会定时执行,并执行查询操作来计算规则结果(例如:触发报警)。该执行在 Prometheus 的内部进行,并在配置规则时自动发生
- 外部用户和 UI 界面可以使用 Prometheus 服务器提供的 HTTP API 来执行 PromQL 查询,这就是仪表盘软件(例如:Grafana,PromLens以及Prometheus内置的WebUI)访问PromQL的方式
PromQL可以应用于许多监控场景,比如临时查询,我们可以用PromQL来对收集到的数据进行实时查询,这有助于我们去调试和诊断遇到的一些问题,我们一般也是直接使用内置的表达式查询界面来执行这类查询
Prometheus可以直接使用基于PromQL对收集的数据进行的查询结果来生成报警,一个完整的报警规则如下
groups:
- name: demo-service-alerts
rules:
- alert: Many5xxErrors
expr: |
(
sum by(path, instance, job) (
rate(demo_api_request_duration_seconds_count{status=~"5..",job="demo"}[1m])
)
/
sum by(path, instance, job) (
rate(demo_api_request_duration_seconds_count{job="demo"}[1m])
) * 100 > 0.5
)
for: 30s
labels:
severity: critical
annotations:
title: "{{$labels.instance}} high 5xx rate on {{$labels.path}}"
description: "The 5xx error rate for path {{$labels.path}} on {{$labels.instance}} is {{$value}}%."
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
除了构成报警规则核心的PromQL表达式(上面的yaml中的"expr"属性),报警规则还包含一切其他的元数据字段
这样配置完成之后,Prometheus会通过一个名为 AlertManager 的组件来发送报警通知,可以配置一些接收器来接收这些报警,比如钉钉、企业微信、WebHook等
# 结果类型
- 抓取目标报告的指标类型:Counter,Guage,Histogram,Summary
- PromQL 表达式的结果数据类型:字符串,标量,瞬时向量或区间向量
PromQL实际上没有直接的指标类型的概念,只关注表达式的结果类型,每个PromQL表达式都有一个类型,每个函数,运算符或其他类型的操作都要求其参数是某种表达式类型,例如:rate()函数要求它的参数是一个区间向量,但是rate()本身评估为一个瞬时向量输出,所以rate()的结果只能用在期望是瞬时向量的地方
也许这样说有点抽象,详细的说一下这 4 种结果类型
string(字符串):字符串只会作为某些函数(如:label_join()和label_replaca())的参数出现
scalar(标量):一个单一的数学值,如1.234,这些数字可以作为某些函数的参数,(如:histogram_quantile(0.9,...)或topk(3,...)),也会出现在算术运算
instant vector(瞬时向量):一组标记的时间序列,每个序列有一个样本,都在同一个时间戳,瞬时向量可以由TSDB时间序列选择器直接产生,如node_cpu_seconds_total,也可以由任何函数或其他转换来获取
node_cpu_seconds_total{cpu="0", mode="idle"} 19165708.75 @ timestamp_1 node_cpu_seconds_total{cpu="0", mode="system"} 381598.72 @ timestamp_1 node_cpu_seconds_total{cpu="0", mode="user"} 23211638.97 @ timestamp_1
range vector(区间向量):一组标记的时间序列,每个序列都有一个随时变化的样本范围,在PromQL中只有两种方法可以生成区间向量,在查询中使用字面区间向量选择器(如:node_cpu_seconds_total[5m]),或使用子查询表达式(如:<expression>[5m:10s]),想要在指定的窗口内聚合一个序列的行为时,区间向量非常有用。像rate(node_cpu_seconds_total[5m]),计算每秒增加率一样,在node_cpu_seconds_total指标的最后5分钟内求平均值
node_cpu_seconds_total{cpu="0", mode="idle"} 19165708.75 @ timestamp_119165136.3 @timestamp_2,19165167.72 @ tinestamp_3 node_cpu_seconds_total{cpu="0", mode="system"} 381598.72 @ timestamp_1381599.98 @ timestamp_2, 381600.58 @ timestamp_3 node_cpu_seconds_total{cpu="0", mode="user"} 23211638.97 @ timestamp_1 23211711.34 @timestamp_2,23211748.64 @ tinestamp_3
# 瞬时查询
瞬时查询用于表格的视图,你想在一个时间点上显示PromQL查询的结果,一个瞬时查询有以下参数:
1.PromQL表达式、2.一个评估的时间戳
在查询的时候可以选择过滤过去的数据,比如(foo[1h])表示查询foo序列近一小时的数据,访问过去的数据。
瞬时查询可以返回任何有效的PromQL表达式类型(字符串,标量,即时和范围向量)
下面来看一个瞬时查询的示例,看看它是如何工作的,比如http_requests_total在指定的时间戳来评估表达式,http_requests_total是一个瞬时向量选择器,它可以选择该时间序列的最新样本,最新意味着查询最近5分钟的样本数据
如果我们在一个有最近样本的时间戳上运行此查询,结果将包含两个序列,每个序列都有一个样本
prometheus_http_requests_total{code="200",job="prometheus",handler="/metrics"}
prometheus_http_requests_total{code="200",job="prometheus",handler="/targets"}
prometheus_http_requests_total{code="200",job="prometheus",handler="/targets"} or prometheus_http_requests_total{code="200",job="prometheus",handler="/metrics"}
2
3
4



我们可以看到每隔5分钟都会有一个新的数据,但是这个数据也可能是不变的
# 区域查询
区域查询主要用于图形,想在一个指定的时间范围内显示一个 PromQL 表达式,范围查询的工作方式与即时查询完全相同,这些查询在指定时间范围的评估步中进行评估,当然,这些后台是高度优化的,在这种情况下 Prometheus 实际上并没有运行许多的独立即时查询
区间查询包括以下参数:PromQL表达式、开始时间、结束时间、评估步长
# 选择时间序列
学习如何用不同的的方式来选择数据,如何在单个时间戳或一段时间范围内基于标签过滤数据,以及如何使用移动时间的方式来选择数据
最简单的PromQL查询就是直接选择具有指定标签名称的序列
例如:以下查询将返回所有具有指标名称 demo_api_request_duration_seconds_count 的序列

由于数据是 demo 产生的,所以数据很多,该查询语句会返回许多相同指标名称的序列,但有不同的标签组合 instance,job,method,path 和 status 等,输出结果如上所示

此结果为区间向量

当我们访问 Graph 的时候 API 会发生变化,因为是一个区间,所以要有始有终的

这里就是区间查询了
过滤全部 method为 GET的数据
PromQL:demo_api_request_duration_seconds_count{method="GET"} PromQL:{name="demo_api_request_duration_seconds_count",method="GET"}

过滤多个标签,使用","来分割多个条件
PromQL:demo_api_request_duration_seconds_count{method="GET",instance="localhost:10000"} PromQL:{_name_="demo_api_request_duration_seconds_count",method="GET",instance="localhost:10000"}
注意:组合使用多条件匹配的时候需要所有的条件都必须满足的时间序列
除了相等之外的,Prometheus还支持其他的几种匹配器类型
- = :等于
- !=:不等于
- =~:正则表达式匹配
- !~:正则表达式不匹配
甚至我们可以完全省略指标名称,比如查询所有path标签的以/api开头的所有序列,但是该查询会查询到具有不同指标名的序列
PromQL:{path=~"/api.*"}

使用不等于来过滤想要的数据 PromQL:demo_api_request_duration_seconds_count{method!="GET"} PromQL:{name="demo_api_request_duration_seconds_count",method != "GET"}
因为部分函数可能要求的是你需要传递一个区间向量,所以你需要添加一个时间,# 无法取Graph PromQL:demo_api_request_duration_seconds_count{method != "GET"}[1m] PromQL:{name="demo_api_request_duration_seconds_count",method != "GET"}[1m]
使用offset <time>来查询过去一小时之前的数据,# 可获取Graph PromQL:demo_memory_usage_bytes{type="free"} offset 1h PromQL:{name="demo_memory_usage_bytes",type="free"} offset 1h