编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

深入理解Prometheus: PromQL查询逻辑详解

wxchong 2024-12-14 15:35:53 开源技术 59 ℃ 0 评论

本文将从逻辑上详细解释promql的查询过程,阅读需要5分钟。

PromQL是一种嵌套函数语言

PromQL与SQL相关的声明式语言不同,是基于函数嵌套实现,可以想象为多个函数的嵌套,内层每个函数的执行结果是外层函数的输入,最外层函数的运行结果就是查询结果。

示例:

# Root of the query, final result, approximates a quantile.
histogram_quantile(
  # 1st argument to histogram_quantile(), the target quantile.
  0.9,
  # 2nd argument to histogram_quantile(), an aggregated histogram.
  sum by(le, method, path) (
    # Argument to sum(), the per-second increase of a histogram over 5m.
    rate(
      # Argument to rate(), the raw histogram series over the last 5m.
      demo_api_request_duration_seconds_bucket{job="demo"}[5m]
    )
  )
)

上述示例中,每个内部的嵌套函数单独拿出来都是一个正确的promql查询,例如rate、sum等

The query builder, analyzer, and explainer for PromQL

PromQL表达式是有类型的,但与通常的不太一样

Prometheus中有两种类型:

指标类型:counter, gauge, histogram, summary, untyped.

表达式类型:string, scalar, instant vector, range vector

string:字符串

scalar:也叫数字常量

instant vector:同一时刻,只有一个样本的多个时序,通常用于生成表格

node_cpu_seconds_total{cpu="0", mode="idle"}   → 19165078.75 @ timestamp_1
node_cpu_seconds_total{cpu="0", mode="system"} →   381598.72 @ timestamp_1
node_cpu_seconds_total{cpu="0", mode="user"}   → 23211630.97 @ timestamp_1

range vector:一段时间内,具有多个样本的多个时序,通常用于画折线图

node_cpu_seconds_total{cpu="0", mode="idle"}   → 19165078.75 @ timestamp_1,  19165136.3 @ timestamp_2, 19165167.72 @ timestamp_3
node_cpu_seconds_total{cpu="0", mode="system"} → 381598.72   @ timestamp_1,   381599.98 @ timestamp_2,   381600.58 @ timestamp_3
node_cpu_seconds_total{cpu="0", mode="user"}   → 23211630.97 @ timestamp_1, 23211711.34 @ timestamp_2, 23211748.64 @ timestamp_3

PromQL忽略指标类型,只支持表达式类型,也就是说不会对处理的数据的指标类型做校验,只要符合表达式类型即可。

比如rate函数参数必须是一个range vector,结果是instant vector,至于是什么指标类型不关心。

比如histogram_quantile只能用于histogram metric,rate只能用于counter,deriv只能用于gauge,如果不按照要求也可以使用,只是算出来的结果没有意义。

Range and instant queries

Instant queries

用途:生成表格视图,只返回某个时刻多个时序的一个样本

参数:1. 查询表达式

2. 时间戳

返回:string, scalar, instant and range vectors

详解:假设我们要查询http_requests_total在指定时刻的值

PromQL会基于指定的时刻,向前找第一个遇到的数据点

最多向前查找5分钟,如果遇到就返回,否则认为空

如果有返回,返回结果中的时间戳是指定的时间戳,而不是数据点真实的时间戳

能找到数据点

返回空

Range queries

用途:生成出图,返回某个时间段内多个时序的多个样本

参数:1. 查询表达式

2. 开始时间

3. 结束时间

4. 间隔

返回:range vectors

详解:假设我们要查询http_requests_total在指定时间段内的值

PromQL会从“开始时间”开始,按指定的”间隔“运行查询表达式,并将结果放入一个range vector中

相当于按指定的间隔,执行了多次instant query,然后将每个结果放入一个range vector中

也遵循最多向前查找5分钟,如果遇到就返回,否则认为空

如果有返回,返回结果中的时间戳是指定的时间戳,而不是数据点真实的时间戳


回溯5分钟规则

Instant query需要“在给定时间给我一组系列的最新样本值”。但如何定义“最新”是个棘手的问题。 Prometheus 没有样本之间固定间隔的概念,因此很难绝对地说是否存在给定系列的“当前”最新样本。如果一个系列的最新样本是一周前的,您可能不希望将其包含在当前时间戳的即时向量选择器的结果中,另一方面,您也不能期望样本与评估时间戳完全匹配,因为 Prometheus TSDB 中的样本在某些时间网格上未对齐并且可以具有任意时间戳。
所以某种妥协策略,既选择不太过时的最新样本,也不需要超快的抓取间隔甚至网格对齐的样本时间戳,所以就有了相对于评估时间戳最多回顾 5 分钟,时间戳早于 5 分钟的样本将从结果中删除。

5 分钟规则是排除旧数据和包含足够新的样本之间的一个很好的折衷方案。但是,在某些情况下,序列在即时向量选择器结果中停留的时间比严格需要的时间长,这很烦人。例如,如果您在 Kubernetes 上运行服务并在标签值中跟踪 pod 名称,那么当您重新部署该服务时,所有系列标识(标签集)都会更改(因为 pod 名称会更改)。您将拥有带有一组 pod 名称的旧系列和带有一组新名称的新系列。但是,在 5 分钟内,您将在图表中同时看到新系列和旧系列,这可能会造成混淆。如果您根据这些数据进行聚合,那就更令人困惑了。如果您计算所有 pod 的内存使用量的总和,那么在 5 分钟内,您将看到总使用量的两倍!
为了解决这个问题,Prometheus 支持将系列标记为显式陈旧:当 Prometheus 检测到一个系列将灭绝(因为它的目标已经消失,或者它不再在目标的抓取中返回,或者因为记录规则停止返回它), Prometheus 为这个系列写了一个明确的过时标记。陈旧标记是 TSDB 中的正常样本,但具有一种特殊的 NaN 样本值来表示陈旧。当即时向量选择器在其评估时间戳之前遇到过时标记作为最后一次看到的样本值时,相应的系列将不会包含在结果中。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表