一起来看看PromQL查询解析。虽然PromQL有操作符、函数、选择器等,但无需被这些细节所困扰。来看看查询的总体性质:PromQL查询是如何结构化和类型化的?随着时间的推移它们是如何评估的?
这里将假设大家对PromQL查询和Prometheus数据模型有大概粗略的了解。
1、PromQL是一种嵌套的函数式语言
不像SQL或其他一些更倾向于命令式的查询语言(<font style="color:rgb(0, 0, 0);">SELECT * FROM...</font>
),PromQL是一种嵌套的函数式语言。这意味着寻找的数据描述为一组嵌套表达式,每个表达式都计算出一个中间值(没有副作用)。每个中间值都用作它周围表达式的参数或操作数,而查询的最外层表达式表示您在表、图或类似用例中看到的最终返回值。
查询示例如下所示:
PromQL表达式不仅是整个查询,而且是查询的任何嵌套部分(如上面的
# Root of the query, final result, approximates a quantile.
histogram_quantile(
# 1st argument to histogram_quantile(), the target quantile.
0.9,
# 2nd argument to histogram_quantile(), an aggregated histogram.
sum by(le, method, path) (
# Argument to sum(), the per-second increase of a histogram over 5m.
rate(
# Argument to rate(), the raw histogram series over the last 5m.
demo_api_request_duration_seconds_bucket{job="demo"}[5m]
)
)
)
<font style="color:rgb(0, 0, 0);">rate(…)</font>
部分),可以单独作为查询运行。在上面的例子中,每个注释行代表一个表达式。
当在PromLabs的PromLens查询可视化工具中分析相同的查询时,包含子表达式的嵌套表达式结构会变得特别清晰:
2、输入的表达式,可能不像你想的那样
Prometheus中有两个“类型”的概念:- 由抓取目标所报告的度量类型:计数器、仪表、直方图、摘要或无类型。
- PromQL表达式的类型:字符串、标量、瞬时向量或范围向量。
- 字符串:类似 “I am a string!”. 这些只作为某些函数(如
**<font style="color:black;">label_join()</font>**
)的参数出现,在PromQL中并不常用。 - 标量:没有标注尺寸的单个数值,如 1.234。您将看到这些函数的数值参数,如
**<font style="color:black;">histogram_quantile(0.9,…)</font>**
或**<font style="color:black;">topk(3,…)</font>**
,以及算术运算。 - 瞬时向量:一组带标签的时间序列,每个序列有一个样本,所有样本都有相同的时间戳。瞬时向量可以直接来自TSDB时间序列选择器,如
**<font style="color:black;">node_cpu_seconds_total</font>**
,也可以来自返回它们的任何函数或其他转换。
node_cpu_seconds_total{cpu="0", mode="idle"} → 19165078.75 @ timestamp_1
node_cpu_seconds_total{cpu="0", mode="system"} → 381598.72 @ timestamp_1
node_cpu_seconds_total{cpu="0", mode="user"} → 23211630.97 @ timestamp_1
- 范围向量:一组带标签的时间序列,每个序列都有一段时间的样本范围。在PromQL中只有两种方法产生范围向量:在查询中使用文字范围向量选择器(如node_cpu_seconds_total[5m]),或者使用子查询(如[5m:10s])。当想要聚合指定时间窗口内的一系列行为时,范围向量非常有用,就像使用
**<font style="color:black;">rate(node_cpu_seconds_total[5m])</font>**
计算**<font style="color:black;">node_cpu_seconds_total</font>**
在过去5分钟内的平均每秒增长率一样。
但是指标类型呢?如果已经使用过PromQL,可能知道某些函数只适用于特定类型的指标!例如,
node_cpu_seconds_total{cpu="0", mode="idle"} → 19165078.75 @ timestamp_1, 19165136.3 @ timestamp_2, 19165167.72 @ timestamp_3
node_cpu_seconds_total{cpu="0", mode="system"} → 381598.72 @ timestamp_1, 381599.98 @ timestamp_2, 381600.58 @ timestamp_3
node_cpu_seconds_total{cpu="0", mode="user"} → 23211630.97 @ timestamp_1, 23211711.34 @ timestamp_2, 23211748.64 @ timestamp_3
<font style="color:rgb(0, 0, 0);">histogram_quantile()</font>
函数只适用于直方图指标,<font style="color:rgb(0, 0, 0);">rate()</font>
只适用于计数器指标,而<font style="color:rgb(0, 0, 0);">deriv()</font>
只适用于仪表。但是PromQL实际上并不检查您是否传入了正确类型的指标——这些函数通常会顺利地运行,并为错误类型的输入指标返回一些无意义的东西,并且由用户决定是否传入符合某些假设的时间序列(比如在直方图的情况下有一个敏感的le标签,或者在计数器的情况下单调增加)。然而,将来很可能会看到像PromLens这样的用户界面试图警告你,如果把一个不兼容的指标类型传递给一个函数。
3、时间是怎么进来的?范围和即时查询!
可能已经注意到,PromQL查询中对时间的唯一引用是相对引用(例如[5m],向后看5分钟)。那么,如何指定绝对图形时间范围,或者在表中显示查询结果的时间戳呢?在PromQL中,这样的时间参数与表达式分开发送给Prometheus查询API,确切的时间参数取决于您发送的查询类型。Prometheus有两种类型的PromQL查询:即时查询和范围查询。3.1即时查询
即时查询用于类似表格的视图,在这些视图中,您希望显示PromQL查询在单个时间点的结果。 即时查询的参数包括:- PromQL表达式。
- 评估时间戳
3.2范围查询
范围查询主要用于图形,其中您希望显示给定时间范围内的PromQL表达式。范围查询的工作方式完全类似于许多完全独立的即时查询,这些查询在给定时间范围内的后续时间步骤中进行评估。当然,这是经过高度优化的,在这种情况下,Prometheus实际上并没有运行很多独立的即时查询。 范围查询包含以下参数:- PromQL表达式。
- 开始时间。
- 结束时间。
- 解析步骤。