PromQL
概述
参考:
Prometheus Query Language(Prometheus 查询语言,简称 PromQL) 是一种提供了查询功能的编程语言,用来实时选择和汇总 时间序列数据。通过 PromQL 可以对监控数据进行筛选、过滤、组合等等操作。使用 PromQL 编写的语句也可以称为 Expression(表达式),表达式的结果可以通过其他方式显示为图形。
PromQL 体验
在 graph 页面,可以在红框位置输入表达式
点击红框内的对话框 并输入关键字,系统会自动弹出可用的 metrics name
表达式直接使用 MetricsName,则展示此时此刻的以 node_cpu_seconds_total 为指标名的所有 TimeSeries(时间序列) 数据
如果需要筛选则可以输入如下图实例的表达式:node_cpu_seconds_total{job=~“external.*”}
筛选出来 job 名开头是 external 的 cpu 情况。允许使用正则表达式,=~表示的就是用过正则来匹配后面的值
Prometheus 通过 MetricsName(指标名称) 及其对应的一组 LabelSet(标签集) 定义唯一的一条时间序列。指标名称反映了监控样本的基本标识,而 label 则在这个基本特征上为采集到的数据提供了多种特征维度。用户可以基于这些特征维度过滤,聚合,统计从而产生新的计算后的一条时间序列。
PromQL 是 Prometheus 内置的数据查询语言,其提供对时间序列数据丰富的查询,聚合以及逻辑运算能力的支持。并且被广泛应用在 Prometheus 的日常应用当中,包括对数据查询、可视化、告警处理当中。可以这么说,PromQL 是 Prometheus 所有应用场景的基础,理解和掌握 PromQL 是 Prometheus 入门的第一课。
PromQL 基本语法
PromQL 没有绝对通用的语法,在不同场景查询条件下,语法也不同。但是,语法必须要有语句,这种语句就称为 Expression(表达式),Expression 可以是简单的字符串,也可以是一个指标名称,甚至是一串基于指标的复杂语法。
在 PromQL 中,任何 Expression(表达式) 或者 subExpression(子表达式) 都可以归为四种类型:
- Instant Vector Selectors(即时向量选择器) # 包含每个时间序列的单个样本的一组时间序列,共享相同的时间戳。
- 即时向量 在有的地方也被翻译为 瞬时向量,都是同一个意思。
- Range Vector Selectors(范围向量选择器) # 包含每个时间序列随时间变化的数据点的一组时间序列。
- 范围向量
- String(字符串) # 一个简单的字符串值(目前未被使用)
- Scalar(标量) # 一个简单的数字浮点值
在这四种表达式中,我们还可以通过 Operators(操作符) 和 Functions(函数) 加工获取到的时间序列数据。
这四种类型,又可以进行统一分类
- Instant Vector Selectors 和 Range Vector Selectors 统称为 TimeSeries Selectors(时间序列选择器)
- 这种表达式会根据 Metrics 来获取指定的时间序列。
- String 和 Scalar 统称为 Literal(字面量)
- 给定不同类型的 Literal,就返回对应类型的的值,Prom 里只支持 string 和 scalar 这两种类型
Expression(表达式)
Instant Vector Selectors(即时向量选择器)
即时向量选择器就是获取通过 Metric 来获取当前最新时间戳上的值,这就是即时的含义(指的是当前最新的值)
根据 MetricName 选择时间序列数据
当我们直接使用 Metrics 查询时,可以查询该 Metrics 下的所有时间序列数据。如:
promhttp_metric_handler_requests_total # 该表达式会返回指标名称为 promhttp_metric_handler_requests_total 的所有时间序列数据:
promhttp_metric_handler_requests_total{code="200", instance="172.38.40.250:9090", job="prometheus"}=(98@1518096812.326)
promhttp_metric_handler_requests_total{code="500", instance="172.38.40.250:9090", job="prometheus"}=(0@1518096812.326)
promhttp_metric_handler_requests_total{code="503", instance="172.38.40.250:9090", job="prometheus"}=(0@1518096812.326)
过滤选择到的时间序列数据
如果想要过滤查询结果,可以根据 metric 中的 Label 来进行匹配,通过在 { }
符号中使用一组 Label 来进一步过滤这些时间序列数据,支持两种匹配模式:完全匹配和正则匹配。可以使用 4 种用于标签匹配的操作符
=
# 完全匹配。通过使用Label="Value"
可以选择那些标签值满足表达式定义的时间序列;!=
# 完全不匹配。反之使用Label!="Value"
则可以根据标签值匹配排除时间序列;=~
# 正则匹配。使用Label=~"RegEx"
表示选择那些标签符合正则表达式定义的时间序列;!~
# 正则不匹配。反之使用Label!~"RegEx"
进行排除;- 正则匹配中,多个表达式之间使用
|
进行分隔:
- 正则匹配中,多个表达式之间使用
例如,如果我们只需要查询所有 promhttp_metric_handler_requests_total 指标中满足标签 code 的值为 200 的时间序列,则可以使用如下表达式:
promhttp_metric_handler_requests_total{code=“200”}
反之使用 code!=“200” 则可以排除这些时间序列:
promhttp_metric_handler_requests_total{code!=“200”}
如果想查询多个环节下的时间序列序列可以使用如下表达式:
promhttp_metric_handler_requests_total{code=~“200|500”}
根据 Label 选择时间序列数据
我们可以把 Label 当作表达式来获取所有具有这些 Label 的 Metrics 的时间序列数据
在 Label 中还可以使用原始标签
Range Vector Selectors(范围向量选择器)
直接通过表达式 http_requests_total 查询时间序列时,返回值中只会包含该时间序列中的最新的一个样本值,这样的返回结果我们称之为瞬时向量。而相应的这样的表达式称之为瞬时向量表达式。
而如果我们想要获取过去一段时间范围内的样本数据时,我们则需要使用范围向量表达式。范围向量表达式 和 瞬时向量表达式 基本一样,唯一的区别在于,范围向量表达式 中我们需要定义时间选择的范围,时间范围通过 [ ]
(这个符号表示:时间范围选择器) 进行定义。
例如:
promhttp_metric_handler_requests_total{}[4m]
# 该表达式将会返回查询到的时间序列中最近 4 分钟的所有样本数据:数据如下
[!Notes]
- 这种查询方式只可以获取到值,并不能生成图表,因为图表中的一条向量是由很多个点组成的,每个点的位置由横轴是 time、纵轴是 value 互相确认得到的。但是这种查询结果会使每个点由多个 time 与多个 value 组成,一个点怎么可能由多个点合成一个呢?这在二维图标上是没法显示出来的。
- 由于有多个值而且还没法展示,所以范围向量一般不会单独使用,而是与 irate()等函数一起使用。以便让多个值根据指定的函数规则聚合成唯一的一个值。
promhttp_metric_handler_requests_total{code="200", instance="172.38.40.250:9090", job="prometheus"}=[
223@1518096812.326
224@1518096817.326
225@1518096822.326
226@1518096827.326
]
promhttp_metric_handler_requests_total{code="200", instance="172.38.40.250:9090", job="prometheus"}=[
0@1518096812.326
0@1518096817.326
0@1518096822.326
0@1518096827.326
]
除了使用 m 表示分钟以外,PromQL 的时间范围选择器支持其它时间单位:
- ms # 毫秒
- s # 秒
- m # 分钟
- h # 小时
- d # 天
- w # 周
- y # 年
Subquery(子查询)
在 [ ]
符号表示的 时间范围选择器 中,可以使用 Subquery(子查询) 功能为时间范围添加 Resolution(分辨率)(有时候也成为 Step(步长)),比如:
promhttp_metric_handler_requests_total{}[4m:30s]
30s 就是 Resolution,表示在 4m 的时间范围中,每隔 30 秒取一个样本值。
Resolution 通常是可省略的,默认值为 Promethesu Server 的 .global.evaluation_interval
子查询之所以叫子查询,通常用在多个 PromQL Functions 的场景,比如
rate(avg_over_time(node_network_receive_bytes_total{device="eth0"}[5m])[6h:5m])
是合法的
rate(avg_over_time(node_network_receive_bytes_total{device="eth0"}[5m])[6h:])
是合法的
rate(avg_over_time(node_network_receive_bytes_total{device="eth0"}[5m])[6h])
是非法的
[!Attention] 其中
avg_over_time(node_network_receive_bytes_total{device="eth0"}[5m]
的结果为即时向量的时间序列,若想基于该结果使用 rate 函数,则必须显式使用 Subquery 指定 Resolution。像上面两个合法的例子示例
Offset modifier(位移修饰符) - 时间位移操作
在瞬时向量表达式或者范围向量表达式中,都是以当前时间为基准:
http_request_total{}
# 瞬时向量表达式,选择当前最新的数据
http_request_total{}[5m]
# 范围向量表达式,选择以当前时间为基准,5 分钟内的数据
而如果我们想查询,5 分钟前的瞬时样本数据,或昨天一天的区间内的样本数据呢? 这个时候我们就可以使用位移操作,位移操作的关键字为 offset。
可以使用 offset 时间位移操作:
http_request_total{} offset 5m
#
http_request_total{}[5m] offset 1d
#
String(字符串) 表达式
直接使用字符串,作为 PromQL 表达式,则会直接返回字符串。
"this is a string"
'these are unescaped: \n \\ \t'
`these are not unescaped: \n ' " \t`
比如下图:
如果通过 API,则是这种样子:
~]# curl "http://172.38.40.244:30001/api/v1/query?query=%22HelloWorld%22"
{"status":"success","data":{"resultType":"string","result":[1610673038.083,"HelloWorld"]}}
Scalar(标量) 表达式
除了使用瞬时向量表达式和区间向量表达式以外,PromQL 还直接支持用户使用标量(Scalar)和字符串(String)。
标量只有一个数字,没有时序。
例如:
10
需要注意的是,当使用表达式 count(http_requests_total),返回的数据类型,依然是瞬时向量。用户可以通过内置函数 scalar()将单个瞬时向量转换为标量。
Operators(运算符)
Prometheus 支持许多二进制和聚合运算符。详见《PromQL Operators》章节
Functions(函数)
Prometheus 支持多种对数据进行操作的函数。详见《PromQL Functions》章节
表达式样例
所有的 PromQL 表达式都必须至少包含一个指标名称(例如 http_request_total),或者一个不会匹配到空字符串的标签过滤器(例如{code=“200”})。
因此以下两种方式,均为合法的表达式: 合法的表达式:
- http_request_total
- http_request_total{}
不合法的表达式:
{job=~".*"}
- 注意,可以使用
'{job=~"..*"}'
来匹配所有 job 的 metric,但是官方不建议这么用,防止意外情况发生
- 注意,可以使用
同时,除了使用{label=value}的形式以外,我们还可以使用内置的__name__标签来指定监控指标名称:
{__name__=~"http_request_total"}
# 合法
{__name__=~"node_disk_bytes_read|node_disk_bytes_written"}
# 合法
即时向量查询结果的示意图
范围向量查询结果示意图
反馈
此页是否对你有帮助?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.