Prometheus ‘@’ 修饰符详解

概述

在 Prometheus 的监控查询语言 PromQL 中,@ 修饰符是一个强大的新特性(自 v2.25.0 引入),它允许查询在特定的、固定的时间点进行计算,而非默认的查询评估时间。这对于解决范围查询(Range Query)中某些聚合函数(如 topk())返回结果数量不确定的问题至关重要。在 SRE 实践中,稳定、可预测的监控查询是分析性能趋势、定位问题和建立可靠 SLI(服务级别指标)的基础。@ 修饰符使得对历史数据进行定点分析和比较变得更加直接和可靠。

核心概念

@ 修饰符的核心作用是将 PromQL 选择器(vector selector、range vector selector 和 subquery)的评估时间固定在一个指定的 Unix 时间戳(float literal)上。这与 offset 修饰符不同,后者是将评估时间相对于当前时间进行偏移。

其基本语法如下:

<vector-selector> @ <timestamp>
<range-vector-selector> @ <timestamp>
<subquery> @ <timestamp>

例如,查询 http_requests_total 在特定时间点 2021-01-04T07:40:00+00:00(Unix 时间戳 1609746000)的值:

http_requests_total @ 1609746000

此外,@ 修饰符还支持两个特殊值:start() 和 end()。

  • 在范围查询中,start() 解析为查询范围的起始时间,end() 解析为结束时间,并且在整个查询的所有步长(step)中保持不变。
  • 在即时查询(Instant Query)中,start() 和 end() 均解析为当前的查询评估时间。

这组特性使得在复杂的范围查询中引用一致的时间点成为可能,从而解决了长期以来 topk() 等函数在范围查询中表现不稳定(结果数量可能超过 k)的痛点。

实践

@ 修饰符最典型的应用场景是固定范围查询中的排序逻辑。一个常见的需求是:在一段时间范围内,持续绘制那些在过去一小时内流量排名前五的服务的当前速率。

如果不使用 @ 修饰符,直接运行 topk(5, rate(http_requests_total[1h])) 作为范围查询,由于每个查询步长都独立计算 topk,最终图表中可能包含数十条甚至上百条时间线,失去了“Top 5”的意义。

使用 @ 修饰符,我们可以将排名逻辑固定在范围查询的结束时间点(end()):

rate(http_requests_total[1m]) 
  and 
topk(5, rate(http_requests_total[1h] @ end()))

查询解析:

  1. topk(5, rate(http_requests_total[1h] @ end())):计算查询时间范围结束时,过去一小时的请求速率,并返回 Top 5 的时间序列标签集合。由于使用了 @ end(),这个“Top 5 列表”在整个范围查询期间是固定不变的。
  2. rate(http_requests_total[1m]):计算每个时间点上,过去一分钟的请求速率。
  3. and 操作符:返回上述两个结果集中标签集合匹配的条目。效果是:在每个时间点上,只绘制那些在查询结束时刻属于 Top 5 的服务的 1 分钟速率曲线。

这种模式可以推广到其他函数,例如使用 histogram_quantile() 固定分位数计算的时间点,或用 sum_over_time() 替换 rate()。

注意: @ 修饰符在 Prometheus v2.25.0 中是实验性特性,需要通过启动标志 --enable-feature=promql-at-modifier 手动启用。

SRE 要点

  • 与可靠性的关联:@ 修饰符极大地提升了监控查询的确定性与可解释性。在排查事件或进行容量规划时,SRE 可以精确地将分析锚定在某个特定的故障时间点(例如 @ 1609746000),对当时各服务的流量、延迟、错误率进行横向对比,避免了因时间窗口滑动造成的混淆。这直接支持了快速、准确的事件响应。
  • 最佳实践与反模式:
    • 最佳实践:将 @ 修饰符与 and、or 等逻辑操作符结合,用于构建“基于某个基准时间的过滤器”或“排行榜”。这对于创建稳定、可重复的 Grafana 仪表板面板非常有用。
    • 常见反模式:在需要动态反映“当前 Top N”的即时查询中滥用 @ 修饰符。此时直接使用不带 @ 的查询更为合适。误用 start() 或 end() 可能导致查询结果与预期不符。
  • 相关指标(SLI/SLO/SLA):在定义和监控复杂的 SLI 时,@ 修饰符有助于创建更清晰的复合指标。例如,你可以定义一个 SLI,专门监控“过去 24 小时内平均延迟最高的 3 个 API 端点”的当前错误率。这为设定针对特定高风险服务的 SLO 提供了精确的数据基础。
  • 可观测性:@ 修饰符增强了对时间序列数据的探索能力。它使得对历史数据进行定点快照分析和跨时间点对比(如比较本周一与上周一同一时刻的性能)变得更加直观,丰富了可观测性的分析维度。