Prometheus PromQL 查询基础:即时查询与范围查询、选择器、时间修饰符与字面量详解

Prometheus PromQL 查询基础:即时查询与范围查询、选择器、时间修饰符与字面量详解
Prometheus PromQL 查询基础即时查询与范围查询、选择器、时间修饰符与字面量详解【免费下载链接】prometheusThe Prometheus monitoring system and time series database.项目地址: https://gitcode.com/GitHub_Trending/pr/prometheus本篇技术指南以 Prometheus 官方文档《Querying basics》为主体系统讲解 PromQLPrometheus Query Language的数据类型、字面量、时间序列选择器、offset与时间修饰符、子查询以及查询引擎的时间语义。读完本文你将能够正确编写即时查询与范围查询、理解 lookback/staleness 机制的底层行为并结合开源仓库中的解析器与引擎源码定位查询行为背后的实现依据。两种查询形态即时查询与范围查询Prometheus 提供了一套函数式查询语言 PromQL让用户能够实时地选择与聚合时间序列数据。向 Prometheus 发送查询请求时请求可以是即时查询instant query在单一时间点求值范围查询range query在起止时间之间以固定步长step间隔多次求值。两种情形下 PromQL 的工作方式完全一致范围查询本质上就是在不同时间戳上多次执行的即时查询。在 Prometheus Web UI 中Table 页签对应即时查询Graph 页签对应范围查询。其他程序则可以通过 HTTP API 获取任意 PromQL 表达式的求值结果。样本Samples浮点样本与原生直方图样本PromQL 在某个时间戳返回的样本值可能是浮点数float也可能是**原生直方图native histogram**样本浮点样本就是一个简单的浮点数原生直方图样本则包含一个完整的直方图包括 count、sum 和各个桶buckets。一个容易混淆的术语约定术语含义histogram sample直方图样本在 PromQL 文档语境下永远指原生直方图classic histogram经典直方图由_bucket、_count、_sum三个后缀的一系列时间序列组成共同描述一个直方图从 PromQL 的视角看经典直方图里只有浮点样本并不存在“经典直方图样本”这一说法。浮点样本与直方图样本都可以具有 counter 或 gauge 的“flavor”语义类型浮点样本不存储自身的 flavor由写查询的人自行注意约定上包含浮点 counter 的时间序列名以_total结尾以帮助区分直方图样本“知道”自己是 counter 还是 gauge因此引擎可以对不匹配的操作给出可靠告警。例如对 gauge 浮点序列使用rate()函数查询不会报错但结果很可能无意义而对 gauge 直方图执行同样的操作查询结果会带有警告注解warning annotation。此外向量vector和时间序列可以同时混合包含浮点样本与直方图样本。表达式语言的数据类型在 Prometheus 表达式语言中一个表达式或子表达式可以求值为四种类型之一Instant vector即时向量——一组时间序列的集合每个时间序列包含一个样本所有样本共享同一时间戳Range vector范围向量——每个时间序列包含一段时间内的多个数据点Scalar标量——简单的数值型浮点值String字符串——简单的字符串值当前尚未使用。不同类型的合法性因使用场景而异对于即时查询上述任意数据类型都可以作为表达式根节点的结果而范围查询只支持标量类型scalar和即时向量类型instant vector的表达式。从源码结构看这四种类型在 类型定义 中以ValueType常量vector、scalar、matrix、string表达DocumentedType()函数把内部类型名映射为文档面向用户的术语如vector→ instant vector、matrix→ range vector可见文档术语与解析器内部术语是一一对应的。原生直方图桶布局的对齐Reconciliation原生直方图可能具有不同的桶布局bucket layout但在执行二元运算和聚合运算前通常可以被转换为兼容的版本。作用于范围向量、且适用于原生直方图的函数同样会执行这种对齐二元运算中对齐是成对pairwise进行的聚合运算与聚合函数中所有直方图样本会被对齐到同一个兼容的桶布局。并非所有桶布局都能被对齐。若操作中遇到不兼容的直方图对应的输出向量元素会从结果中移除并带上 warn 级别的注解annotation。字面量LiteralsPromQL 中不存在“直方图字面量”。以下是各类字面量的语法说明。字符串字面量字符串字面量由单引号、双引号或反引号界定。单引号与双引号字符串遵循与 Go 相同的转义规则反斜杠开始转义序列后跟a、b、f、n、r、t、v或\也可用八进制\nnn、十六进制\xnn、\unnnn、\Unnnnnnnn表示特定字符。反引号字符串不解析转义字符。注意与 Go 不同Prometheus不会丢弃反引号内的换行符。this is a string these are unescaped: \n \\ \t these are not unescaped: \n \t浮点字面量与时间单位标量浮点值可以写成如下格式空格仅为提高可读性[-]?( [0-9]*\.?[0-9]([eE][-]?[0-9])? | 0[xX][0-9a-fA-F] | [nN][aA][nN] | [iI][nN][fF] )示例23 -2.43 3.4e-9 0x8f -Inf NaN此外下划线_可用于十进制或十六进制数字之间以提升可读性1_000_000 .123_456_789 0x_53_AB_F3_82浮点字面量也用于表示以秒为单位的时间长度。十进制整数可以与以下时间单位组合单位含义ms毫秒s秒1s 1000msm分钟1m 60s忽略闰秒h小时1h 60md天1d 24h忽略夏令时w周1w 7dy年1y 365d忽略闰日给十进制整数加上单位等价于以纯浮点字面量表示相同秒数1s # 等价于 1 2m # 等价于 120 1ms # 等价于 0.001 -2h # 等价于 -7200以下写法不合法0xABm # 十六进制数不允许加单位后缀 1.5h # 时间单位不能与浮点数组合 Infd # ±Inf 与 NaN 不允许加单位后缀多个单位可以拼接但必须从大到小排列且同一单位在一个字面量中只能出现一次1h30m # 等价于 5400s即 5400 12h34m56s # 等价于 45296s即 45296 54s321ms # 等价于 54.321持续时间表达式Duration expressions在需要时间持续时间的地方——即范围向量选择器和offset持续时间——都可以使用算术表达式。在范围向量中rate(http_requests_total[5m * 2]) # 10 分钟范围 rate(http_requests_total[(52) * 1m]) # 7 分钟范围在 offset 持续时间中http_requests_total offset (1h / 2) # 30 分钟偏移 http_requests_total offset ((2 ^ 3) * 1m) # 8 分钟偏移使用offset加持续时间表达式时必须用括号包裹整个表达式不加括号的话offset 计算只会取第一个持续时间值。支持的运算符遵循常规优先级规则运算符含义加法-减法*乘法/除法%取模^幂运算持续时间表达式中还可使用以下函数step()解析为范围查询的步长step width即时查询中解析为0srange()解析为范围查询的总时长end time − start time即时查询中解析为0s。与 end()结合尤其有用例如max_over_time(metric[range()] end())可以在整个查询范围内回溯min_of(duration, duration)返回两者中较小者用于给持续时间设置上限max_of(duration, duration)返回两者中较大者用于强制最小值。例如max_of(step(), 5s)保证持续时间不小于5smin_of(range(), 1h)把持续时间上限封顶在1h。注意修饰符中不支持持续时间表达式。等价持续时间示例5m * 2等价于10m或600s10m - 1m等价于9m或540s(52) * 1m等价于7m或420s1h / 2等价于30m或1800s4h % 3h等价于1h或3600s(2 ^ 3) * 1m等价于8m或480sstep() 1等价于查询步长增加1smax_of(step(), 5s)等价于查询步长与5s中的较大者min_of(2 * step() 5s, 5m)等价于“查询步长两倍加5s”与5m中的较小者。从源码看持续时间表达式在解析后并不立即求值而是以 AST 节点DurationExpr形式挂在OriginalOffsetExpr/RangeExpr/StepExpr字段上见 AST 定义在执行前由 durationVisitor 统一计算。该访问器处理三类节点VectorSelectoroffset 表达式、MatrixSelector范围表达式和SubqueryExproffset、step、range 三类表达式。求值过程还包含重要的健壮性检查见 calculateDuration显式拒绝 NaN 与 ±Inf防止其绕过边界检查后在time.Duration转换时产生未定义值拒绝超出 int64 纳秒表示范围的持续时间即 |seconds| 不超过 2^63/1e9除零、取模零会直接报错范围向量与子查询的范围/步长不允许为负或零而 offset 允许负值用于时间前向比较。时间序列选择器选择器是 PromQL 的基本构件指明查询引擎要获取哪些数据。即时向量选择器即时向量选择器在一给定时间戳处选择一组时间序列并为每个序列返回一个样本值。最简单的形式只写指标名结果是一个即时向量包含所有该指标名的时间序列http_requests_total返回的值是查询求值时间戳之前最近的那个样本即时查询对应查询时间范围查询对应当前 step。使用修饰符 可以覆盖选择所依据的时间戳。只有当时间序列的最近样本距当前时刻不超过 lookback period 时该序列才会被返回。可以用花括号{}追加逗号分隔的标签匹配器进一步过滤http_requests_total{jobprometheus,groupcanary}标签匹配操作符共四个操作符含义与给定字符串完全相等!与给定字符串不相等~与给定字符串正则匹配!~与给定字符串正则不匹配正则匹配是完全锚定的env~foo等价于env~^foo$。例如选择staging、testing、development三种环境下、HTTP 方法非GET的所有http_requests_total时间序列http_requests_total{environment~staging|testing|development,method!GET}匹配空值的标签匹配器也会选中根本没有该标签的时间序列。同一标签名可以出现多个匹配器且全部匹配才返回结果。给定数据集http_requests_total http_requests_total{replicarep-a} http_requests_total{replicarep-b} http_requests_total{environmentdevelopment}查询http_requests_total{environment}会匹配并返回前三条它们都没有environment标签而排除http_requests_total{environmentdevelopment}。查询http_requests_total{replica!rep-a,replica~rep.*}只会匹配http_requests_total{replicarep-b}。向量选择器必须指定指标名或至少一个不匹配空字符串的标签匹配器。以下表达式非法{job~.*} # Bad!而下面两个都合法因为它们含有不匹配空标签值的匹配器{job~.} # Good! {job~.*,methodget} # Good!从源码看这条规则由解析器在 validate 阶段强制执行“A Vector selector must contain at least one non-empty matcher to prevent implicit selection of all metrics (e.g. by a typo)”——防止因拼写错误而隐式选中全部指标。标签匹配器也可以作用于指标名本身通过匹配内部__name__标签实现。例如http_requests_total等价于{__name__http_requests_total}且!、~、!~也可使用。以下表达式选中所有名字以job:开头的指标{__name__~job:.*}指标名不得是bool、on、ignoring、group_left、group_right这些关键字之一。以下表达式非法on{} # Bad!变通方案是借助__name__标签{__name__on} # Good!范围向量选择器范围向量字面量与即时向量字面量工作方式相同但选择的是从当前时刻向前回溯一段时间内的样本序列。语法上在向量选择器末尾用方括号[]追加一个浮点字面量指定向前取多少秒的数据。常见写法使用带时间单位的字面量如[5m]。范围区间是左开右闭的时间戳恰好在左边界上的样本被排除时间戳恰好在右边界上的样本被包含。示例——选择所有指标名为http_requests_total且job标签为prometheus的时间序列在 5 分钟内的所有值http_requests_total{jobprometheus}[5m]offset 修饰符offset修饰符可以改变查询中单个即时向量或范围向量的时间偏移。例如以下表达式返回相对于当前查询求值时刻过去 5 分钟时http_requests_total的值http_requests_total offset 5m注意offset修饰符必须紧跟选择器例如这样写是对的sum(http_requests_total{methodGET} offset 5m) // GOOD.而下面这种是错误的sum(http_requests_total{methodGET}) offset 5m // INVALID.对范围向量同理。下面返回http_requests_total一周前的 5 分钟速率rate(http_requests_total[5m] offset 1w)查询历史样本时负数 offset可以实现向未来方向的时间比较rate(http_requests_total[5m] offset -1w)注意这允许查询“超前于”其求值时间向前看。 修饰符修饰符可以改变查询中单个即时向量或范围向量的求值时间。修饰符接受的时间值是用浮点字面量表示的Unix 时间戳。例如以下表达式返回2021-01-04T07:40:0000:00时http_requests_total的值http_requests_total 1609746000与offset相同必须紧跟选择器。这样写是对的sum(http_requests_total{methodGET} 1609746000) // GOOD.而下面这种是错误的sum(http_requests_total{methodGET}) 1609746000 // INVALID.对范围向量同理返回2021-01-04T07:40:0000:00时刻的 5 分钟速率rate(http_requests_total[5m] 1609746000)修饰符支持上文描述的全部数字字面量形式。它还可以与offset修饰符一起使用此时 offset 相对于修饰符指定的时间生效无论两个修饰符的书写顺序如何结果相同# offset 在 之后 http_requests_total 1609746000 offset 5m # offset 在 之前 http_requests_total offset 5m 1609746000此外start()与end()可作为修饰符的特殊取值对范围查询二者分别解析为该范围查询的起始与结束时间且对所有 step 保持不变对即时查询start()与end()都解析为求值时间。http_requests_total start() rate(http_requests_total[5m] end())注意修饰符允许查询超前于其求值时间。从源码结构看修饰符在解析器中以Timestamp *int64字段绝对时间戳和StartOrEnd ItemType字段标记start()/end()承载于 VectorSelector 与 SubqueryExpr 上Offset字段则存放执行时实际使用的偏移量由原始 offset、时间、求值时间与子查询偏移共同计算得出。子查询Subquery子查询允许你针对给定的时间范围与分辨率运行一次即时查询。子查询的结果是一个范围向量。语法instant_query [ range : [resolution] ] [ float_literal ] [ offset float_literal ]其中resolution分辨率即子查询内部的 step是可选的默认取全局求值间隔。从 AST 结构看SubqueryExpr 同时携带Range/RangeExpr范围、Step/StepExpr分辨率与OriginalOffset/OriginalOffsetExpr偏移三者均可使用持续时间表达式并在 durationVisitor 中统一求值。运算符与函数Prometheus 支持大量二元运算符与聚合运算符详见表达式语言运算符页也支持若干对数据操作的函数详见表达式语言函数页。注释PromQL 支持以#开头的行注释# This is a comment正则表达式Prometheus 中所有正则表达式均使用 RE2 语法Google RE2具有线性时间复杂度的确定性匹配特性且正则匹配始终是全程锚定的。常见陷阱GotchasStaleness陈旧样本与 lookback period查询采样所用的时间戳独立于实际现存时间序列数据选择这主要是为了支持聚合sum、avg等这类场景——被聚合的多个时间序列在时间上往往并不精确对齐。正因其独立性Prometheus 必须为每个相关时间序列在这些时间戳上分配一个值它的做法是取“距该时间戳不超过 lookback period 之前的最新样本”。lookback period 默认 5 分钟可以通过--query.lookback-delta命令行标志设置见命令行参考也可以在单个查询中通过lookback_delta参数覆盖。从源码看默认值定义于 engine.go 的defaultLookbackDelta 5 * time.Minute当LookbackDelta为 0 时引擎自动回退到该默认值命令行标志在 main.go 中注册为query.lookback-delta描述为 “The maximum lookback duration for retrieving metrics during expression evaluations and federation.”。行为边界由 TestQueryLookbackDelta 测试用例验证样本恰好落后一个默认 lookback5 分钟时会被查询取到再落后一个毫秒则不再取到。陈旧stale语义当某个 target 的抓取或规则求值不再返回先前存在的时间序列样本时该序列会被标记为 stale当 target 被移除时其先前抓取的时间序列也会很快被标记为 stale若查询的采样时间戳晚于序列被标记为 stale 的时刻则不再为该序列返回值之后若重新摄入新样本则按预期返回序列在不再导出、或 target 不存在时变 stale它们会从图表中最后采集样本的时刻消失之后查询不再返回。一个例外某些自行打时间戳的 exporter 行为不同——其停止导出的序列会在消失前保持最后一个值默认 5 分钟。track_timestamps_staleness配置可以改变该行为。避免慢查询与过载当查询需要处理大量数据时绘图可能会超时甚至压垮服务器或浏览器。因此在未知数据上构建查询时始终先在 Prometheus 表达式浏览器的表格视图tabular view中构建查询直到结果集看起来合理最多几百条、而非几千条时间序列。只有当数据被充分过滤或聚合后再切换到图表模式。如果表达式即席ad-hoc绘图仍然太慢就通过记录规则预先记录计算结果。这一点在 Prometheus 中尤其关键像api_http_requests_total这样裸的指标名选择器可能扩展为数千条带不同标签的时间序列。同时要记住对大量时间序列做聚合的表达式即使输出只有少数几条序列也会给服务器带来负载——正如在关系数据库中对某一整列求和即便输出只是一个数字也会很慢。小结与延伸阅读主题关键要点即时/范围查询范围查询 不同时间戳上的多次即时查询Table 页签即时Graph 页签范围样本类型浮点样本与原生直方图样本直方图自带 counter/gauge 语义可产生可靠性告警四种数据类型instant vector、range vector、scalar、string未用范围查询仅支持 scalar 与 instant vector字面量字符串三种引号、浮点含下划线、十六进制、时间单位ms/s/m/h/d/w/y 从大到小拼接持续时间表达式 - * / % ^与step()、range()、min_of()、max_of()offset 表达式需加括号中不支持选择器空值匹配器选中无该标签的序列{job~.*}非法至少需一个非空匹配器offset/均须紧跟选择器支持负 offset 与start()/end()可超前求值时间Staleness默认 5 分钟 lookback--query.lookback-delta或单查询lookback_delta可调更多学习材料可参考仓库中的 示例文档建议初学者先通过示例入门、运算符、函数与 HTTP API 参考页深入实现可阅读 promql/parser/parse.go解析与校验、promql/parser/ast.goAST 节点定义、promql/durations.go持续时间表达式求值与 promql/engine.go查询引擎。【免费下载链接】prometheusThe Prometheus monitoring system and time series database.项目地址: https://gitcode.com/GitHub_Trending/pr/prometheus创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

最新新闻

日新闻

周新闻

月新闻