查询 Prometheus

Prometheus 提供了一种名为 PromQL(Prometheus 查询语言)的功能查询语言,允许用户实时选择和聚合时间序列数据。表达式的结果可以以图形的形式显示,在 Prometheus 的表达式浏览器中以表格数据形式查看,或者通过 HTTP API 供外部系统使用。

示例

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

表达式语言数据类型

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

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

根据用例(例如,在绘图与显示表达式输出时),只有其中一些类型在用户指定的表达式的结果中是合法的。例如,返回瞬时向量的表达式是唯一可以绘制的类型。

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

  • 摄取原生直方图必须通过 特性标志 启用。
  • 一旦原生直方图被摄取到 TSDB 中(即使在再次禁用特性标志后),瞬时向量和范围向量现在都可能包含不是简单浮点数(浮点数样本)而是完整直方图(直方图样本)的样本。一个向量可能包含浮点数样本和直方图样本的混合。

字面量

字符串字面量

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

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

从 2.54 版本开始,浮点数字面量也可以使用时间持续时间的语法表示,其中时间持续时间转换为对应于时间持续时间表示的秒数的浮点值。这是一个实验性功能,可能会发生变化。

示例

1s # Equivalent to 1.0
2m # Equivalent to 120.0
1ms # Equivalent to 0.001

时间序列选择器

时间序列选择器负责选择时间序列和原始或推断的样本时间戳和值。

时间序列选择器不要与可以执行时间序列选择器的更高级别的瞬时和范围查询概念混淆。更高级别的瞬时查询将在某个时间点评估给定的选择器,但是范围查询将在最小和最大时间戳之间的多个不同时间点以规则的步长评估选择器。

瞬时向量选择器

瞬时向量选择器允许选择一组时间序列以及在给定时间戳(某个时间点)每个时间序列的单个样本值。在最简单的形式中,只指定指标名称,这将导致一个瞬时向量,其中包含具有此指标名称的所有时间序列的元素。

此示例选择所有具有 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!

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

范围向量选择器

范围向量字面量的工作方式与瞬时向量字面量类似,但它们会选择从当前时间点开始的一系列样本。从语法上讲,在向量选择器的末尾附加方括号 ([]) 中的 时间持续时间 以指定应为每个生成的范围向量元素获取值的回溯时间。范围是一个闭区间,即时间戳与范围的任一边界重合的样本仍然包含在选择中。

在此示例中,我们选择过去 5 分钟内记录的所有具有指标名称 http_requests_totaljob 标签设置为 prometheus 的时间序列的所有值

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

时间持续时间

时间持续时间指定为一个数字,后面紧跟着以下单位之一

  • ms - 毫秒
  • s - 秒
  • m - 分钟
  • h - 小时
  • d - 天 - 假设一天始终为 24 小时
  • w - 周 - 假设一周始终为 7 天
  • y - 年 - 假设一年始终为 365 天1

1 对于一年中的天数,忽略闰日,反之,对于分钟,忽略闰秒。

时间持续时间可以通过连接组合。单位必须从最长到最短排序。给定的单位只能在时间持续时间中出现一次。

以下是一些有效时间持续时间的示例

5h
1h30m
5m
10s

从 2.54 版本开始,时间持续时间也可以使用浮点数字面量的语法表示,表示时间持续时间的秒数。这是一个实验性功能,可能会发生变化。

示例

1.0 # Equivalent to 1s
0.001 # Equivalent to 1ms
120 # Equivalent to 2m

偏移修饰符

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

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 <duration> ]

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

运算符

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

函数

Prometheus 支持多个用于对数据进行操作的函数。这些在表达式语言函数页面中详细描述。

注释

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

    # This is a comment

注意事项

陈旧性

在查询期间选择采样数据的时戳与实际存在的时序数据无关。这主要是为了支持诸如聚合(sumavg 等)之类的用例,其中多个聚合的时序在时间上并不完全对齐。由于它们相互独立,因此 Prometheus 需要为每个相关的时序分配这些时戳下的值。它是通过在回溯期内获取此时间戳之前的最新样本来实现的。回溯期默认为 5 分钟。

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

如果在时序被标记为陈旧后的采样时戳处评估查询,则不会为该时序返回任何值。如果随后为该时序摄取了新样本,则将按预期返回这些样本。

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

一些导出器会在样本上添加自己的时间戳,因此行为有所不同:停止导出的序列会将最后一个值保留(默认)5 分钟,然后再消失。track_timestamps_staleness 设置可以更改此设置。

避免慢查询和过载

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

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

本文档是开源的。请通过提交问题或拉取请求来帮助改进它。