Prometheus 子查询 (Subquery)
概述
Prometheus 子查询是自 2.7 版本引入的一项重要 PromQL 功能。它允许在单个即时查询(Instant Query)中嵌套执行一个范围查询(Range Query),从而极大简化了过去需要通过录制规则(Recording Rules)间接实现的复杂多时间尺度数据分析场景。在 SRE 实践中,子查询提供了快速分析历史数据、进行临时性故障排查的灵活性,但其使用也需要权衡性能影响。
核心概念
一个子查询的语法结构如下:<instant_query> [ <range>: [ <resolution> ] ] [ offset <duration> ]。它本质上是在执行外部查询之前,先对内部查询进行一个类似 /api/v1/query_range API 的范围计算,并将其结果(一个范围向量)传递给外部函数。
<instant_query>: 子查询内部需要执行的瞬时查询表达式。<range>: 定义内部查询的时间范围,类似于范围选择器(如[5m])。<resolution>(可选): 指定子查询的计算步长(step)。若未指定,则使用 Prometheus 全局评估间隔(evaluation_interval)作为默认值。这个步长与外部查询的评估时间独立对齐。offset <duration>(可选): 允许子查询相对于当前查询执行时间进行偏移。
子查询的计算是独立的,其时间对齐(由 <range> 和可选的 <resolution> 决定)不依赖于外部查询或规则评估周期。这意味着同一个子查询在不同时间点评估时,会重新计算其完整范围,这与录制规则预先计算并存储结果的方式有本质区别。
实践
基础用例:多时间尺度聚合
最常见的动机是,先以较高的频率(较小的 range)计算一个指标(如 rate),然后对这个结果在更长的时间窗口内进行聚合(如 max_over_time)。在子查询出现之前,这必须通过录制规则分两步完成。
假设我们想查看过去 1 小时内,每 5 分钟的 HTTP 请求速率的最大值。使用子查询可以在一个查询中完成:
max_over_time(
rate(http_requests_total[5m])[1h:1m]
)
解析:
- 子查询
rate(http_requests_total[5m])[1h:1m]表示:在当前时间点之前的 1 小时范围内,以 1 分钟的步长,重复执行rate(http_requests_total[5m])计算。 - 得到的结果是一个包含过去 1 小时内所有 1 分钟步长上的 5 分钟速率值的范围向量。
- 外部函数
max_over_time()从这个范围向量中提取最大值。
嵌套与默认分辨率
子查询可以嵌套使用。例如,计算速度(rate)的导数(deriv)在过去 10 分钟内的最大值:
max_over_time(
deriv(
rate(distance_covered_meters_total[1m])[5m:1m]
)[10m:]
)
注意内层子查询 [5m:1m] 指定了 1 分钟的步长,而最外层 [10m:] 使用了冒号 :,表示省略分辨率参数。此时,deriv() 函数的结果将以 Prometheus 全局的 evaluation_interval 作为步长进行范围查询。
性能考量与最佳实践
尽管子查询非常便捷,但 不加甄别地使用会对 Prometheus 性能造成显著影响。因为每次执行包含子查询的即时查询(无论是通过 API 调用还是作为告警/记录规则),都会触发子查询的完整重新计算,这可能非常耗时且消耗大量内存。
关键实践:
- 用于临时分析:子查询最适合用于临时性的故障排查和一次性分析,而不是长期的、高频次的监控或告警规则。
- 转化为录制规则:对于需要反复计算、用于仪表板或告警规则的子查询逻辑,最终应将其转化为一个或多个录制规则,以预计算并存储结果,从而提升查询效率和系统稳定性。
- 避免嵌套过深:在录制规则内部嵌套子查询是不推荐的,这会加剧性能问题。如果录制规则的计算确实需要类似的逻辑,应将其拆解为多个顺序执行的、更简单的录制规则。
SRE 要点
- 与可靠性的关联:子查询本身是 PromQL 的查询能力,直接影响的是 Prometheus 服务的查询可靠性和性能。滥用复杂子查询可能导致查询超时或 OOM,进而影响基于这些查询的告警和仪表板功能,最终降低整个监控系统的可靠性。
- 可观测性:子查询扩展了即时查询的能力边界,使工程师能够对历史数据进行更深度的“在线”分析,这对于事后故障分析(Post-mortem)和探索性诊断非常有价值。在查询时,可以将其视为一次“即时”的、针对历史窗口的范围查询。
- 最佳实践与常见反模式:
- 最佳实践:将子查询作为探索性工具和原型设计工具。在确认其分析逻辑稳定、重要后,应迁移到录制规则。
- 反模式:在 Grafana 面板中直接使用高频、复杂的子查询;在
for子句较短的告警规则中嵌套重型子查询;试图用子查询完全替代录制规则的预计算功能。
- 相关指标 (SLI/SLO/SLA):
- 查询延迟 SLI:子查询的性能直接影响
prometheus_rule_evaluation_duration_seconds和整体的查询延迟 SLO。复杂子查询会显著增加这些指标的数值。 - 资源使用 SLI:子查询的计算会临时增加 Prometheus 进程的 CPU 和内存使用量,可能影响
process_resident_memory_bytes和process_cpu_seconds_total等指标。 - 为保障 Prometheus 服务的 SLO,团队应对核心告警和仪表板查询中的子查询使用进行代码审查,并设定性能预算。
- 查询延迟 SLI:子查询的性能直接影响