子查询支持
2019年1月28日作者 Ganesh Vernekar
简介
顾名思义,子查询是查询的一部分,它允许您在查询中执行范围查询,这在以前是不可能的。这是一个长期存在的功能请求:prometheus/prometheus/1227 。
支持子查询的拉取请求 最近已合并到 Prometheus 中,并将在 Prometheus 2.7 中提供。下面让我们来详细了解它。
动机
有时,您希望使用较低分辨率/范围(例如 5m)的 rate 来发现问题,同时又想在更高范围(例如 1h 的 max_over_time)上聚合这些数据。
以前,对于单个 PromQL 查询来说,上述操作是不可能的。如果您想为告警规则或图表对查询进行范围选择,就需要基于该查询建立一条记录规则,然后对由记录规则创建的指标执行范围选择。例如:max_over_time(rate(my_counter_total[5m])[1h])。
当您希望快速获取跨越数天或数周的数据结果时,可能需要等待相当长的时间,直到记录规则中积累了足够的数据才能使用。忘记添加记录规则可能会令人沮丧。而且为查询的每一步都创建记录规则会很繁琐。
有了子查询支持,所有这些等待和挫败感都将成为过去。
子查询
子查询类似于 /api/v1/query_range API 调用,但它嵌入在即时查询中。子查询的结果是一个范围向量。
在慕尼黑举行的 2018 年 Prometheus 开发者峰会上,Prometheus 团队就子查询的语法达成了共识。以下是关于子查询支持的峰会笔记 ,以及一份用于实现子查询支持的简要语法设计文档 。
<instant_query> '[' <range> ':' [ <resolution> ] ']' [ offset <duration> ]
<instant_query>相当于/query_rangeAPI 中的query字段。<range>和offset <duration>类似于范围选择器。<resolution>是可选的,相当于/query_rangeAPI 中的step。
当未指定分辨率时,将采用全局评估间隔作为子查询的默认分辨率。此外,子查询的步长是独立对齐的,不依赖于父查询的评估时间。
示例
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>-30m到end=<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:] )
在大多数情况下,您会需要默认的评估间隔,即规则默认的评估间隔。在您希望降低或提高计算频率的情况下(例如,对于那些您可能希望减少计算频率的昂贵查询),自定义分辨率会很有帮助。
结语
尽管子查询在替代记录规则方面非常方便,但不必要地使用它们会带来性能问题。为了提高效率,繁重的子查询最终应转换为记录规则。
也不建议在记录规则中使用子查询。如果您确实需要在记录规则中使用子查询,不如创建更多的记录规则。