子查询支持
2019年1月28日作者 Ganesh Vernekar
简介
顾名思义,子查询是查询的一部分,它允许你在一个查询中进行范围查询,而这在以前是不可能的。这是一个长期存在的特性请求:prometheus/prometheus/1227 。
用于支持子查询的pull request 最近已合并到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 调用,但嵌入在一个即时查询中。子查询的结果是一个范围向量。
Prometheus团队在2018年在慕尼黑举行的Prometheus开发者峰会上就子查询的语法达成了一致。以下是关于子查询支持的峰会笔记 ,以及一份简短的用于实现子查询支持的语法设计文档 。
<instant_query> '[' <range> ':' [ <resolution> ] ']' [ offset <duration> ]
<instant_query>等同于/query_rangeAPI 中的query字段。<range>和offset <duration>类似于范围选择器。<resolution>是可选的,等同于/query_rangeAPI 中的step。
当未指定解析度时,全局评估间隔将作为子查询的默认解析度。此外,子查询的步长独立对齐,不依赖于父查询的评估时间。
示例
min_over_time 函数内的子查询在1分钟的解析度下,返回过去30分钟内 http_requests_total 指标的5分钟费率。这等同于使用 query=rate(http_requests_total[5m]), end=<now>, start=<now>-30m, step=1m 进行 /query_range API 调用,并取所有接收值的最小值。
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:] )
在大多数情况下,你会需要默认的评估间隔,这是规则默认评估的间隔。自定义解析度在你想计算得更频繁或不那么频繁的情况下会很有用,例如,计算成本高昂的查询,你可能希望计算的频率较低。
结语
虽然子查询可以方便地替代录制规则,但过度使用它们会带来性能问题。复杂的子查询最终应为了效率而转换为录制规则。
也不建议在录制规则中使用子查询。如果你确实需要在录制规则中使用子查询,请创建更多的录制规则。