查询基础知识

Prometheus 提供了一种名为 PromQL(Prometheus 查询语言)的函数式查询语言,允许用户实时选择和聚合时间序列数据。

当您向 Prometheus 发送查询请求时,它可以是*即时查询*(在某个时间点进行评估),也可以是*范围查询*(在开始和结束时间之间的等间隔步长进行评估)。PromQL 在这两种情况下工作方式完全相同;范围查询就像在不同时间戳上多次运行即时查询一样。

在 Prometheus UI 中,“Table”选项卡用于即时查询,“Graph”选项卡用于范围查询。

其他程序可以通过 HTTP API 获取 PromQL 表达式的结果。

示例

本文档是 Prometheus 语言参考。为了学习,最好从一些 示例 开始。

样本

PromQL 返回的给定时间戳的样本值可能是一个浮点数或一个原生直方图。浮点样本只是一个浮点数,而原生直方图样本包含完整的直方图,包括计数、总和和桶。

请注意,PromQL 文档中的“直方图样本”一词始终指原生直方图。“经典直方图”一词指的是一组时间序列,这些时间序列包含带有 _bucket_count_sum 后缀的浮点样本,它们共同描述了一个直方图。从 PromQL 的角度来看,它们只包含浮点样本,没有“经典直方图样本”。

浮点样本和直方图样本都可以具有计数器或仪表“风味”。具有计数器或仪表风味的浮点样本通常分别简称为“计数器”或“仪表”,而它们的直方图对应物则称为“计数器直方图”或“仪表直方图”。浮点样本不存储其风味,将其风味留给用户在编写 PromQL 查询时进行考虑。(按照惯例,包含浮点计数器的时间序列名称以 _total 结尾,以帮助区分。)

由于直方图样本“知道”它们的计数器或仪表风味,这使得能够对不匹配的操作进行可靠的警告。例如,将 rate 函数应用于仪表浮点数很可能产生无意义的结果,但查询会正常处理。但是,如果应用于仪表直方图,查询结果将带有警告注解。

表达式语言数据类型

在 Prometheus 的表达式语言中,表达式或子表达式可以评估为四种类型之一

  • 即时向量 - 一组时间序列,每个时间序列包含一个样本,所有样本共享相同的时间戳
  • 范围向量 - 一组时间序列,每个时间序列包含一段时间内的数据点范围
  • 标量 - 一个简单的数值浮点值
  • 字符串 - 一个简单的字符串值;目前未使用

根据用例(例如,在绘制图表时与显示表达式输出时),只有某些类型是用户指定表达式的合法结果。对于即时查询,以上任何数据类型都允许作为表达式的根。 范围查询仅支持标量类型和即时向量类型的表达式。

向量和时间序列都可以包含浮点样本和直方图样本的混合。

直方图存储桶布局的协调

原生直方图可以有不同的存储桶布局,但它们通常可以转换为兼容的版本,以便对它们应用二进制和聚合操作。作用于原生直方图的范围向量函数也执行这种协调。在二进制操作中,这种协调是成对执行的,在聚合操作和函数中,所有直方图样本都被协调到一个兼容的存储桶布局。

并非所有存储桶布局都可以协调。如果在操作中遇到不兼容的直方图,则从结果中删除相应的输出向量元素,并用警告级别的注解标记。更多详细信息可以在原生直方图规范中找到。

字面量

下一节将描述各种类型的字面量。请注意,没有“直方图字面量”。

字符串字面量

字符串字面量用单引号、双引号或反引号表示。

PromQL 遵循与 Go 相同的转义规则 。对于单引号或双引号中的字符串字面量,反斜杠开始一个转义序列,后面可以跟 abfnrtv\。可以使用八进制(\nnn)或十六进制(\xnn\unnnn\Unnnnnnnn)表示法提供特定字符。

相反,在反引号表示的字符串字面量中不会解析转义字符。重要的是要注意,与 Go 不同,Prometheus 不会丢弃反引号中的换行符。

示例

"this is a string"
'these are unescaped: \n \\ \t'
`these are not unescaped: \n ' " \t`

浮点文字量和时间持续时间

标量浮点值可以以字面整数或浮点数形式书写,格式为(为方便阅读,仅包含空格)

[-+]?(
      [0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?
    | 0[xX][0-9a-fA-F]+
    | [nN][aA][nN]
    | [iI][nN][fF]
)

示例

23
-2.43
3.4e-9
0x8f
-Inf
NaN

此外,下划线(_)可用于十进制或十六进制数字之间以提高可读性。

示例

1_000_000
.123_456_789
0x_53_AB_F3_82

浮点文字量也用于指定持续时间(秒)。为了方便起见,十进制整数可以与以下时间单位结合使用

  • ms – 毫秒
  • s – 秒 – 1s 等于 1000ms
  • m – 分钟 – 1m 等于 60s(忽略闰秒)
  • h – 小时 – 1h 等于 60m
  • d – 天 – 1d 等于 24h(忽略所谓的夏令时)
  • w – 周 – 1w 等于 7d
  • y – 年 – 1y 等于 365d(忽略闰日)

在十进制整数后添加上述单位之一,表示等效秒数的另一种表示形式,就像裸浮点文字量一样。

示例

1s # Equivalent to 1.
2m # Equivalent to 120.
1ms # Equivalent to 0.001.
-2h # Equivalent to -7200.

以下示例起作用

0xABm # No suffixing of hexadecimal numbers.
1.5h # Time units cannot be combined with a floating point.
+Infd # No suffixing of ±Inf or NaN.

可以通过连接有后缀的整数来组合多个单位。单位必须从长到短排序。给定单位在每个浮点文字量中只能出现一次。

示例

1h30m # Equivalent to 5400s and thus 5400.
12h34m56s # Equivalent to 45296s and thus 45296.
54s321ms # Equivalent to 54.321.

时间序列选择器

这些是指示 PromQL 获取哪些数据的基本构建块。

即时向量选择器

即时向量选择器允许在给定时间戳(特定时间点)选择一组时间序列和一个样本值。最简单的形式是仅指定度量名称,这将生成包含此度量名称的所有时间序列元素的即时向量。

返回值将是查询评估时间戳(对于即时查询)或查询中的当前步长(对于范围查询)的该时间点之前(包括该时间点)的最新样本。 @ 修饰符允许覆盖选择所基于的时间戳。只有当时间序列的最新样本在查找周期之内时,才会返回时间序列。

此示例选择具有 http_requests_total 度量名称的所有时间序列,并为每个时间序列返回最新的样本

http_requests_total

可以通过在花括号({})中添加逗号分隔的标签匹配器列表来进一步过滤这些时间序列。

此示例仅选择具有 http_requests_total 度量名称,并且其 job 标签设置为 prometheusgroup 标签设置为 canary 的时间序列

http_requests_total{job="prometheus",group="canary"}

还可以否定匹配标签值,或将标签值与正则表达式进行匹配。存在以下标签匹配运算符

  • =:选择与提供的字符串完全相等的标签。
  • !=:选择与提供的字符串不相等的标签。
  • =~:选择与提供的字符串正则表达式匹配的标签。
  • !~:选择与提供的字符串正则表达式不匹配的标签。

正则表达式匹配是完全锚定的。env=~"foo" 的匹配被视为 env=~"^foo$"

例如,这会选择所有 stagingtestingdevelopment 环境下的 http_requests_total 时间序列,以及非 GET 的 HTTP 方法。

http_requests_total{environment=~"staging|testing|development",method!="GET"}

匹配空标签值的标签匹配器也选择所有根本没有设置特定标签的时间序列。可以为同一个标签名称设置多个匹配器。

例如,给定数据集

http_requests_total
http_requests_total{replica="rep-a"}
http_requests_total{replica="rep-b"}
http_requests_total{environment="development"}

查询 http_requests_total{environment=""} 将匹配并返回

http_requests_total
http_requests_total{replica="rep-a"}
http_requests_total{replica="rep-b"}

并将排除

http_requests_total{environment="development"}

可以为同一个标签名称使用多个匹配器;所有匹配器都必须通过才能返回结果。

查询

http_requests_total{replica!="rep-a",replica=~"rep.*"}

然后将匹配

http_requests_total{replica="rep-b"}

向量选择器必须指定一个名称或至少一个不匹配空字符串的标签匹配器。以下表达式是非法的

{job=~".*"} # Bad!

相比之下,这些表达式是有效的,因为它们都有一个不匹配空标签值的选择器。

{job=~".+"}              # Good!
{job=~".*",method="get"} # Good!

标签匹配器也可以通过匹配内部 __name__ 标签来应用于度量名称。例如,表达式 http_requests_total 等同于 {__name__="http_requests_total"}。除了 =!==~!~)之外的匹配器也可以使用。以下表达式选择所有名称以 job: 开头的度量

{__name__=~"job:.*"}

度量名称不得为关键字 boolonignoringgroup_leftgroup_right。以下表达式是非法的

on{} # Bad!

一种绕过此限制的方法是使用 __name__ 标签

{__name__="on"} # Good!

范围向量选择器

范围向量文字量的工作方式类似于即时向量文字量,不同之处在于它们从当前时刻选择一个样本范围。语法上,一个浮点文字量附加在方括号([])中,位于向量选择器的末尾,以指定需要为每个结果范围向量元素获取多少秒前的样本。通常,浮点文字量使用带有一个或多个时间单位的语法,例如 [5m]。范围是左开右闭区间,即时间戳与范围左边界重合的样本将被排除在选择之外,而时间戳与范围右边界重合的样本将被包含在选择之内。

在此示例中,我们选择所有具有度量名称 http_requests_total 并且 job 标签设置为 prometheus 的时间序列,并在 5 分钟内记录的所有值。

http_requests_total{job="prometheus"}[5m]

偏移修饰符

offset 修饰符允许更改查询中各个即时向量和范围向量的时间偏移。

例如,以下表达式返回 http_requests_total 相对于当前查询评估时间 5 分钟前的值

http_requests_total offset 5m

请注意,offset 修饰符始终需要紧跟在选择器后面,即以下示例是正确的

sum(http_requests_total{method="GET"} offset 5m) // GOOD.

而以下示例是不正确

sum(http_requests_total{method="GET"}) offset 5m // INVALID.

范围向量也支持相同的方式。这返回了 http_requests_total 在一周前 5 分钟的速率

rate(http_requests_total[5m] offset 1w)

当查询过去的时间样本时,负偏移量将允许向前的时间比较

rate(http_requests_total[5m] offset -1w)

请注意,这允许查询超前于其评估时间。

@ 修饰符

@ 修饰符允许更改查询中各个即时向量和范围向量的评估时间。提供给 @ 修饰符的时间是 Unix 时间戳,并用浮点文字量表示。

例如,以下表达式返回 http_requests_total2021-01-04T07:40:00+00:00 的值

http_requests_total @ 1609746000

请注意,@ 修饰符始终需要紧跟在选择器后面,即以下示例是正确的

sum(http_requests_total{method="GET"} @ 1609746000) // GOOD.

而以下示例是不正确

sum(http_requests_total{method="GET"}) @ 1609746000 // INVALID.

范围向量也支持相同的方式。这返回了 http_requests_total2021-01-04T07:40:00+00:00 的 5 分钟速率

rate(http_requests_total[5m] @ 1609746000)

@ 修饰符支持上面描述的所有数字文字表示。它与 offset 修饰符一起使用,其中偏移量是相对于 @ 修饰符时间应用的。结果与修饰符的顺序无关。

例如,这两个查询将产生相同的结果

# offset after @
http_requests_total @ 1609746000 offset 5m
# offset before @
http_requests_total offset 5m @ 1609746000

此外,start()end() 也可以用作 @ 修饰符的特殊值。

对于范围查询,它们分别解析为范围查询的开始和结束,并且对于所有步长都保持不变。

对于即时查询,start()end() 都解析为评估时间。

http_requests_total @ start()
rate(http_requests_total[5m] @ end())

请注意,@ 修饰符允许查询超前于其评估时间。

子查询

子查询允许您在给定的范围和分辨率下运行即时查询。子查询的结果是范围向量。

语法:<instant_query> '[' <range> ':' [<resolution>] ']' [ @ <float_literal> ] [ offset <float_literal> ]

  • <resolution> 是可选的。默认为全局评估间隔。

运算符

Prometheus 支持许多二进制和聚合运算符。这些在表达式语言运算符页面中有详细描述。

函数

Prometheus 支持多种函数来操作数据。这些在表达式语言函数页面中有详细描述。

注释

PromQL 支持以 # 开头的行注释。示例

    # This is a comment

正则表达式

Prometheus 中的所有正则表达式都使用 RE2 语法 

正则表达式匹配始终是完全锚定的。

注意事项

陈旧性

在查询期间,用于对数据进行采样的时戳独立于实际存在的当前时间序列数据。这主要是为了支持聚合(sumavg 等)之类的用例,其中多个聚合的时间序列在时间上不精确对齐。由于它们的独立性,Prometheus 需要在这些时间戳为每个相关时间序列分配一个值。它通过获取在查找周期之前最新的样本来做到这一点。查找周期默认为 5 分钟,但可以通过 --query.lookback-delta 标志设置,或通过 lookback_delta 参数在单个查询中覆盖。

如果目标抓取或规则评估不再为以前存在的时间序列返回样本,则该时间序列将被标记为陈旧。如果删除了目标,则之前检索到的时间序列将在删除后不久被标记为陈旧。

如果在比时间序列被标记为陈旧之后的时间戳处对查询进行评估,则不会为该时间序列返回值。如果随后为此时间序列摄取了新样本,它们将按预期返回。

当时间序列不再导出,或者目标不再存在时,时间序列将变为陈旧。这样的时间序列将在其最后收集的样本时间点从图中消失,并且在它们被标记为陈旧后不会在查询中返回。

一些导出器(将自己的时间戳放在样本上)会获得不同的行为:停止导出的系列会在消失前(默认)保留最后的值 5 分钟。track_timestamps_staleness 设置可以改变这一点。

避免慢查询和过载

如果查询需要处理大量数据,图形化它可能会导致超时或使服务器或浏览器过载。因此,在构造未知数据的查询时,始终先在 Prometheus 表达式浏览器的表格视图中构建查询,直到结果集看起来合理(最多几百个时间序列,而不是几千个)。只有在您充分过滤或聚合了数据后,才切换到图形模式。如果表达式仍然需要太长时间才能即时绘制图表,请通过录制规则预先录制它。

这对于 Prometheus 的查询语言尤其重要,其中裸度量名称选择器如 api_http_requests_total 可能会扩展到具有不同标签的数千个时间序列。此外,请记住,即使输出仅为少量时间序列,聚合了许多时间序列的表达式也会在服务器上产生负载。这类似于在关系数据库中对某一列的所有值求和会很慢,即使输出值只是一个数字。

本页内容