请参与 Prometheus 用户调研(2026 年 3 月版) ,帮助社区确定未来开发工作的优先级!

子查询支持

2019年1月28日作者 Ganesh Vernekar

简介

正如标题所示,子查询是查询的一部分,允许您在查询内执行范围查询,这在以前是无法实现的。这是一个长期以来的功能请求:prometheus/prometheus/1227 

子查询支持的合并请求 最近已合并到 Prometheus 中,并将在 Prometheus 2.7 版本中提供。让我们在下面深入了解它。

动机

有时,您可能希望使用低分辨率/范围(例如 5m)的 rate 来发现问题,同时在大范围(例如 1hmax_over_time)内聚合此数据。

此前,上述操作无法在单个 PromQL 查询中完成。如果您想在告警规则或图表中对查询进行范围选择,则需要基于该查询创建一个记录规则,并对记录规则生成的指标执行范围选择。示例:max_over_time(rate(my_counter_total[5m])[1h])

当您想快速获取跨越数天或数周的数据结果时,可能需要等待很长时间,直到记录规则中积累了足够的数据才能使用。忘记添加记录规则可能会令人沮丧,并且为查询的每个步骤都创建记录规则也相当繁琐。

有了子查询支持,所有的等待和烦恼都将迎刃而解。

子查询

子查询类似于 /api/v1/query_range API 调用,但嵌入在即时查询(instant query)中。子查询的结果是一个范围向量(range vector)。

Prometheus 团队在慕尼黑举行的 2018 年 Prometheus 开发者峰会上就子查询语法达成了共识。以下是峰会关于子查询支持的笔记 ,以及实现子查询支持所使用的语法设计文档 

<instant_query> '[' <range> ':' [ <resolution> ] ']' [ offset <duration> ]
  • <instant_query> 等同于 /query_range API 中的 query 字段。
  • <range>offset <duration> 类似于范围选择器。
  • <resolution> 是可选的,等同于 /query_range API 中的 step

如果不指定分辨率,则默认使用全局评估间隔(evaluation interval)作为子查询的分辨率。此外,子查询的步长是独立对齐的,不依赖于父查询的评估时间。

示例

min_over_time 函数内部的子查询返回过去 30 分钟内 http_requests_total 指标的 5 分钟速率,分辨率为 1 分钟。这等同于执行了一个 /query_range API 调用,其中 query=rate(http_requests_total[5m]), end=<now>, start=<now>-30m, step=1m,并对接收到的所有值取最小值。

min_over_time( rate(http_requests_total[5m])[30m:1m] )

分解

  • rate(http_requests_total[5m])[30m:1m] 是子查询,其中 rate(http_requests_total[5m]) 是要执行的查询。
  • rate(http_requests_total[5m])start=<now>-30mend=<now> 执行,分辨率为 1m。请注意,start 时间是独立与 1m 的步长对齐的(对齐后的步骤为 0m 1m 2m 3m ...)。
  • 最后,上述所有评估的结果被传递给 min_over_time()

下面是一个嵌套子查询及使用默认分辨率的示例。最内层的子查询获取 distance_covered_meters_total 在一段时间范围内的速率。我们利用该结果获取速率的 deriv()(导数),同样是在一段时间范围内。最后取所有导数的最大值。请注意,最内层子查询的 <now> 时间相对于外层 deriv() 子查询的评估时间。

max_over_time( deriv( rate(distance_covered_meters_total[1m])[5m:1m] )[10m:] )

在大多数情况下,您会需要默认的评估间隔,即规则默认评估的间隔。自定义分辨率在您希望以较低/较高频率进行计算时非常有用,例如,您可能希望以较低的频率计算开销较大的查询。

结语

尽管子查询在替代记录规则时非常方便,但不必要地使用它们会带来性能影响。为了效率,复杂的子查询最终应转换为记录规则。

此外,不建议在记录规则内部使用子查询。如果您确实需要在记录规则中使用子查询,请考虑创建更多的记录规则来拆分逻辑。