查询基础

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

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

在 Prometheus UI 中,“Table” 标签页用于即时查询,“Graph” 标签页用于范围查询。

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

示例

本文是 Prometheus 基础语言参考。为了学习,从一些示例开始可能会更容易。

表达式语言数据类型

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

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

根据使用场景(例如,是绘图还是显示表达式的输出),只有部分类型是用户指定表达式的合法结果。对于即时查询,上述任何数据类型都可以作为表达式的根。而范围查询仅支持标量类型和即时向量类型的表达式。

关于实验性原生直方图的说明

  • 必须通过特性标志启用原生直方图的摄取。
  • 一旦原生直方图被摄取到时序数据库(TSDB)中(即使之后再次禁用该特性标志),即时向量和范围向量现在都可能包含不只是简单浮点数(浮点样本)而是完整直方图(直方图样本)的样本。一个向量可能包含浮点样本和直方图样本的混合。请注意,PromQL 文档中的“直方图样本”始终指原生直方图。经典直方图被分解为多个浮点样本的序列。从 PromQL 的角度看,没有“经典直方图样本”。
  • 与浮点样本一样,直方图样本也可以有计数器(counter)或仪表盘(gauge)的“风格”,分别将其标记为计数器直方图或仪表盘直方图。与浮点样本不同的是,直方图样本“知道”它们的风格,这使得可以可靠地对不匹配的操作发出警告(例如,对仪表盘直方图的范围向量应用 rate 函数)。
  • 原生直方图可以有不同的桶布局,但它们通常可以转换为兼容版本以对其应用二元和聚合操作。并非所有分桶模式都如此。如果在操作中遇到不兼容的直方图,相应的输出向量元素将从结果中移除,并标记一个警告级别的注释。更多细节可以在原生直方图规范中找到。

字面量

字符串字面量

字符串字面量由单引号、双引号或反引号指定。

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 时间序列,且 HTTP 方法不为 GET

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_totaljob 标签设置为 prometheus 的时间序列选择在 5 分钟前记录的所有值

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

offset 修饰符

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

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

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 时间戳,并用浮点数字面量描述。

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

http_requests_total @ 1609746000

请注意,@ 修饰符总是需要紧跟在选择器之后,即以下是正确的

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

而以下是_不正确_的

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

对于范围向量也是如此。这将返回在 2021-01-04T07:40:00+00:00http_requests_total 的 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 语法

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

注意事项

过时性

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

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

如果在时间序列被标记为过时后的某个采样时间戳评估查询,那么该时间序列将不会返回任何值。如果之后为该时间序列摄取了新样本,它们将按预期返回。

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

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

避免慢查询和过载

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

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

本页内容