查询基础
Prometheus 提供了一种名为 PromQL (Prometheus Query Language) 的函数式查询语言,用户可以借此实时选择和聚合时间序列数据。
当您向 Prometheus 发送查询请求时,它可以是在某个时间点评估的_即时查询_,也可以是在起始和结束时间之间以等间距步骤评估的_范围查询_。PromQL 在每种情况下的工作方式完全相同;范围查询就像是在不同时间戳多次运行的即时查询。
在 Prometheus UI 中,“Table”选项卡用于即时查询,“Graph”选项卡用于范围查询。
其他程序可以通过 HTTP API 获取 PromQL 表达式的结果。
示例
本文档是 Prometheus 基础语言参考。为了学习,从一些示例开始可能会更容易。
样本
PromQL 在给定时间戳返回的样本值可以是浮点数或原生直方图。浮点数样本是一个简单的浮点数,而原生直方图样本包含一个完整的直方图,包括计数、总和和桶。
请注意,PromQL 文档中的“直方图样本”一词始终指原生直方图。“经典直方图”一词指的是一组包含浮点数样本的时间序列,其后缀为 `_bucket`、`_count` 和 `_sum`,它们共同描述一个直方图。从 PromQL 的角度来看,这些只包含浮点数样本,没有“经典直方图样本”。
浮点数样本和直方图样本都可以具有计数器或仪表盘“风格”。具有计数器或仪表盘风格的浮点数样本通常分别简称为“计数器”或“仪表盘”,而它们的直方图对应物则称为“计数器直方图”或“仪表盘直方图”。浮点数样本不存储其风格,这需要用户在编写 PromQL 查询时考虑其风格。(按照惯例,包含浮点计数器的时间序列名称以 `_total` 结尾,以帮助区分。)
由于直方图样本“知道”其计数器或仪表盘风格,这使得可以对不匹配的操作发出可靠的警告。例如,将 `rate` 函数应用于仪表盘浮点数很可能会产生一个无意义的结果,但查询将毫无怨言地处理。但是,如果将其应用于仪表盘直方图,查询结果将附带一个警告。
表达式语言数据类型
在 Prometheus 的表达式语言中,表达式或子表达式可以计算为四种类型之一
- 即时向量 - 一组时间序列,其中每个时间序列包含一个样本,所有样本共享相同的时间戳
- 范围向量 - 一组时间序列,其中每个时间序列包含一段时间内的数据点范围
- 标量 - 一个简单的数字浮点值
- 字符串 - 一个简单的字符串值;目前未使用
根据使用情况(例如,绘图与显示表达式的输出),只有其中一些类型可以作为用户指定表达式的合法结果。对于即时查询,上述任何数据类型都可以作为表达式的根。 范围查询仅支持标量类型和即时向量类型的表达式。
向量和时间序列都可能包含浮点样本和直方图样本的混合。
直方图桶布局的协调
原生直方图可以有不同的桶布局,但它们通常可以转换为兼容版本,以便对其应用二元和聚合操作。作用于适用于原生直方图的范围向量的函数也会执行此类协调。在二元操作中,此协调是成对执行的,在聚合操作和函数中,所有直方图样本都会协调到一个兼容的桶布局。
并非所有桶布局都可以协调,如果在操作中遇到不兼容的直方图,相应的输出向量元素将从结果中移除,并标记有警告级别的注释。更多详细信息可以在原生直方图规范中找到。
字面量
以下部分描述了各种类型的字面量值。请注意,没有“直方图字面量”。
字符串字面量
字符串字面量由单引号、双引号或反引号指定。
PromQL 遵循与 Go 相同的转义规则 。对于单引号或双引号中的字符串字面量,反斜杠开始一个转义序列,其后可以是 `a`、`b`、`f`、`n`、`r`、`t`、`v` 或 `\`。可以使用八进制 (`\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 等于 1000msm– 分钟 – 1m 等于 60s(忽略闰秒)h– 小时 – 1h 等于 60md– 天 – 1d 等于 24h(忽略所谓的夏令时)w– 周 – 1w 等于 7dy– 年 – 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` 标签设置为 `prometheus` 且 `group` 标签设置为 `canary` 的时间序列
http_requests_total{job="prometheus",group="canary"}
也可以对标签值进行否定匹配,或者根据正则表达式匹配标签值。存在以下标签匹配操作符
=:选择与提供的字符串完全相等的标签。!=:选择与提供的字符串不相等的标签。=~:选择与提供的字符串进行正则表达式匹配的标签。!~:选择与提供的字符串不进行正则表达式匹配的标签。
正则表达式匹配是完全锚定的。 `env=~"foo"` 的匹配被视为 `env=~"^foo$"`。
例如,这将选择 `staging`、`testing` 和 `development` 环境以及除 `GET` 之外的 HTTP 方法的所有 `http_requests_total` 时间序列。
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:.*"}
指标名称不能是关键字 `bool`、`on`、`ignoring`、`group_left` 和 `group_right` 之一。以下表达式是非法的
on{} # Bad!
解决此限制的方法是使用 `__name__` 标签
{__name__="on"} # Good!
范围向量选择器
范围向量字面量的工作方式类似于即时向量字面量,不同之处在于它们选择从当前时刻回溯的样本范围。语法上,在向量选择器的末尾附加一个浮点数字面量并用方括号(`[]`)括起来,以指定为每个结果范围向量元素应获取多长时间之前的值。通常,浮点数字面量使用带有一个或多个时间单位的语法,例如`[5m]`。范围是一个左开右闭的区间,即时间戳与范围左边界重合的样本被排除在选择之外,而与范围右边界重合的样本则包含在选择之内。
在此示例中,我们选择所有指标名称为 `http_requests_total` 且 `job` 标签设置为 `prometheus` 的时间序列在过去5分钟内记录的所有值
http_requests_total{job="prometheus"}[5m]
偏移修饰符
`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:00` 时的 `http_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:00` 时 `http_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` 这样的裸指标名称选择器可能会扩展到数千个具有不同标签的时间序列。另外,请记住,即使输出只是少量时间序列,聚合许多时间序列的表达式也会在服务器上产生负载。这类似于在关系数据库中对一列的所有值求和会很慢,即使输出值只是一个数字。