[译] Prometheus 运算符
承蒙大家厚爱,我的《Go语言之路》的纸质版图书已经上架京东,有需要的朋友请点击 此链接 购买。
Prometheus 支持许多二元和聚合运算符。
原文链接 OPERATORS
二元运算
Prometheus 的查询语言支持基本的逻辑运算和算术运算。
算术二元运算符
Prometheus 支持以下二元算术运算符:
+
(加法)-
(减法)*
(乘法)/
(除法)%
(取模)^
(幂/指数运算)
二元运算操作符支持 scalar/scalar(标量/标量)
、vector/scalar(向量/标量)
、和 vector/vector(向量/向量)
之间的操作。
在两个标量之间进行算数运算的结果还是一个标量。
在瞬时向量和标量之间,运算符应用于向量中每个数据样本的值。例如,如果时间序列瞬时向量乘以2,则结果是另一个向量,其中原始向量的每个样本值都乘以2。metric 名称被丢弃。
在两个瞬时向量之间,对左侧向量中的每个条目及其右侧向量中的匹配元素应用二进制算术运算符,输出到结果向量中,分组标签成为输出标签集。metric 名称被丢弃。在右侧向量中没有匹配项的条目不会出现在结果中。
三角运算符
Prometheus 支持以下以弧度为单位的三角二元运算符:
atan2
(基于 https://pkg.go.dev/math#Atan2)
三角运算符允许使用向量匹配在两个向量上执行三角函数,这在普通函数中是不可用的。它们的行为方式与算术运算符相同。
比较运算符
Prometheus 有以下二进制比较运算符:
==
(相等)!=
(不相等)>
(大于)<
(小于)>=
(大于等于)<=
(小于等于)
布尔运算符被应用于 scalar/scalar(标量/标量)
、vector/scalar(向量/标量)
,和vector/vector(向量/向量)
。默认情况下布尔运算符只会根据时间序列中样本的值,对时间序列进行过滤。可以通过在运算符后面使用 bool
修饰符来改变布尔运算的默认行为。使用 bool 修改符后,布尔运算不会对时间序列进行过滤,而是直接依次瞬时向量中的各个样本数据与标量的比较结果 0
或者 1
。
在两个标量之间,必须提供bool修饰符,这些运算符根据比较结果产生另一个标量0(false)或1(true)。
在瞬时向量和标量之间,这些运算符应用于向量中每个数据样本的值,比较结果为假的向量元素从结果向量中删除。如果提供了bool修饰符,则将被丢弃的向量元素的值为0,将被保留的向量元素值为1。如果提供了bool修饰符,则会删除度量名称。
在两个瞬时向量之间,这些运算符默认情况下充当过滤器,应用于匹配条目。表达式不为真或在表达式的另一侧找不到匹配的向量元素将从结果中删除,而其他元素将传播到结果向量中,分组标签将成为输出标签集。如果提供了bool修饰符,那么原本会被丢弃的向量元素将具有值0,而将被保留的向量元素则具有值1,分组标签再次成为输出标签集。如果提供了bool修饰符,则会删除度量名称。
逻辑/集二进制运算符
以下这些逻辑/集二进制运算符仅在瞬时向量之间定义:
and
(并且)or
(或者)unless
(排除)
vector1 and vector2
产生一个由 vector1
的元素组成的向量,其中vector2
的元素具有完全匹配的标签集。其他元素被删除。度量名称和值从左侧向量中继承。
vector1 or vector2
产生的向量包含 vector1
的所有原始元素(标签集+值),此外还包含vector2
的所有元素,这些元素在vector1
中没有匹配的标签集。
vector1 unless vector2
产生一个由 vector1
中存在的元素组成的向量,而vector2
中没有具有完全匹配标签集的元素。两个向量中的所有匹配元素都将被删除。
向量匹配
向量之间的操作试图为左侧的每个条目在右侧向量中找到匹配的元素。匹配行为有两种基本类型:一对一(one-to-one)和多对一(many-to-one)/一对多(one-to-many)。
匹配关键字
提供以下矢量匹配关键字在具有不同标签集的系列之间进行匹配:
on
ignoring
提供给匹配关键字的标签列表将决定如何组合向量。示例可以在一对一向量匹配和多对一和一对多向量匹配中找到。
Group modifiers
这些组修饰符支持多对一/一对多向量匹配:
group_left
group_right
标签列表可以提供给组修改器,其中包含要包含在结果度量中的“一侧”标签。
多对一和一对多匹配是高级用例,应仔细考虑。通常情况下,正确使用 ignoring(<labels>)
就能获得所需的结果。
分组修饰符只能用于比较和运算。默认情况下,作为and
、unless
和or
操作与右侧向量中所有可能的条目匹配。
一对一向量匹配
一对一从操作的每一侧找到一对唯一的条目。在默认情况下,这是一个遵循vector1 <operator> vector2
格式的操作。如果两个条目具有完全相同的标签集和相应的值,则它们匹配。ignoring
关键字允许在匹配时忽略某些标签,而 on
关键字允许将考虑的标签集减少到提供的列表中:
<vector expr> <bin-op> ignoring(<label list>) <vector expr>
<vector expr> <bin-op> on(<label list>) <vector expr>
示例输入:
method_code:http_errors:rate5m{method="get", code="500"} 24
method_code:http_errors:rate5m{method="get", code="404"} 30
method_code:http_errors:rate5m{method="put", code="501"} 3
method_code:http_errors:rate5m{method="post", code="500"} 6
method_code:http_errors:rate5m{method="post", code="404"} 21
method:http_requests:rate5m{method="get"} 600
method:http_requests:rate5m{method="del"} 34
method:http_requests:rate5m{method="post"} 120
查询示例:
method_code:http_errors:rate5m{code="500"} / ignoring(code) method:http_requests:rate5m
这将返回一个结果向量,其中包含在过去5分钟内测量的每种方法状态代码为500的HTTP请求的分数。如果不加ignoring(code)
,就不会有匹配结果,因为这些指标数据没有相同的标签。带有 put
和 del
方法的条目不匹配,不会出现在结果中:
{method="get"} 0.04 // 24 / 600
{method="post"} 0.05 // 6 / 120
多对一和一对多向量匹配
多对一和一对多匹配是指“一”那一侧的每个向量元素都可以与“多”那一侧的多个元素匹配的情况。这必须使用 group_left
或group_right
修饰符明确请求,其中left/right确定哪个向量具有更高的基数。
<vector expr> <bin-op> ignoring(<label list>) group_left(<label list>) <vector expr>
<vector expr> <bin-op> ignoring(<label list>) group_right(<label list>) <vector expr>
<vector expr> <bin-op> on(<label list>) group_left(<label list>) <vector expr>
<vector expr> <bin-op> on(<label list>) group_right(<label list>) <vector expr>
用 group 修饰符提供的标签列表包含来自“ one”端的附加标签,这些标签将包含在结果度量中。因为标签上只能出现在其中一个列表中。结果向量的每个时间序列必须是唯一可识别的。
查询示例:
method_code:http_errors:rate5m / ignoring(code) group_left method:http_requests:rate5m
在这种情况下,左侧向量的每个方法标签值都包含一个以上的条目。因此,我们使用 group_left
来表示。现在,右侧的元素将与左侧具有相同方法标签的多个元素相匹配:
{method="get", code="500"} 0.04 // 24 / 600
{method="get", code="404"} 0.05 // 30 / 600
{method="post", code="500"} 0.05 // 6 / 120
{method="post", code="404"} 0.175 // 21 / 120
聚合运算
Prometheus支持以下内置聚合运算符,可用于聚合单个即时向量的元素,从而生成一个包含较少聚合值元素的新向量:
sum
(求和)min
(最小值)max
(最大值)avg
(平均值)group
(结果向量中的所有值都是1)stddev
(标准差)stdvar
(标准差异)count
(计算向量中元素的数量)count_values
(对 value 进行计数)bottomk
(样本值最小的 k 个元素)topk
(样本值最大的k个元素)quantile
(在维度上计算φ分位数(0≤φ≤1))
这些运算符可以用来聚合所有标签维度,也可以通过包含一个 without
或 by
子句来保留不同的维度。这些子句可以在表达式之前或之后使用。
<aggr-op> [without|by (<label list>)] ([parameter,] <vector expression>)
或
<aggr-op>([parameter,] <vector expression>) [without|by (<label list>)]
label list
是一个未引号的标签列表,它可能包含一个后面的逗号,即(label1, label2)
和(label1, label2,)
都是有效的语法。
without
从结果向量中删除列出的标签,而所有其他标签都保留在输出中。by
会执行相反的操作,它会删除by
子句中未列出的标签,即使它们的标签值在向量的所有元素之间都是相同的。
parameter
仅对 count_values
、quantile
、topk
和bottomk
是必需的。
count_values
为每个唯一的样本值输出一个时间序列。每个系列都有一个附加标签。该标签的名称由聚合参数给出,标签值是唯一的样本值。每个时间序列的值是样本值出现的次数。
topk
和 bottomk
不同于其他聚合器,它们在结果向量中返回输入样本的子集,包括原始标签。by
和 without
只用于桶输入向量。
quantile
计算 φ-quantile,这个值在 N 个度量值中以 φ * N 排列。提供 φ 作为聚合参数。例如,quantile(0.5, ...)
计算中位数,quantile(0.95, ...)
计算95分位数。对于 φ = NaN
,返回 NaN
。对于 φ < 0,返回-Inf
。对于 φ > 1,返回 +Inf
。
举个例子:
如果指标 http_requests_total
的时间序列按application
, instance
, and group
展开,我们可以通过以下方式计算每个 application和 group 在所有实例上看到的http请求总数:
sum without (instance) (http_requests_total)
相当于:
sum by (application, group) (http_requests_total)
如果我们只对所有 application 中看到的HTTP请求总数感兴趣,我们可以简单地写:
sum(http_requests_total)
想要查询二进制文件每个构建版本的数量,我们可以写:
count_values("version", build_version)
为了获得所有实例中最大的5个HTTP请求计数,我们可以写:
topk(5, http_requests_total)
运算符优先级
在 Prometheus 系统中,二元运算符优先级从高到低的顺序为:
^
*
,/
,%
,atan2
+
,-
==
,!=
,<=
,<
,>=
,>
and
,unless
or
相同优先级的运算符是左关联运算符。例如,2 * 3 % 2
相当于 (2 * 3) % 2
。然而,^
是右关联运算,因此 2 ^ 3 ^ 2
等同于 2 ^ (3 ^ 2)
。
原生直方图
原生直方图是一项试验性功能。必须通过特征标志启用本地直方图的摄取功能。一旦摄取了本地直方图,就可以对其进行查询(即使功能标志再次被禁用)。不过,本地直方图的运算符支持仍然非常有限。
即使涉及直方图样本,逻辑/集合二进制运算符也能按预期运行。它们只检查是否存在矢量元素,不会根据元素的样本类型(浮点或直方图)改变操作行为。count
聚合运算符的工作原理与此类似。
完全支持两个本地直方图之间的二元 +
和 -
运算,以及用于聚合本地直方图的sum
与avg
聚合运算符。即使涉及的直方图有不同的数据桶布局,数据桶也会自动进行适当转换,以便执行操作。(如果其中一个运算符需要聚合直方图样本和浮点样本的混合样本,则会从输出向量中完全删除相应的向量元素。
二进制 *
运算符可以在任意顺序的本地直方图和浮点之间使用,而二进制/
运算符可以在精确顺序的本地直方图和浮点之间使用。
所有其他运算符(以及上述运算符未提及的情况)的行为都没有意义。它们要么将直方图样本视为值为0的浮点样本,要么(在标量和向量之间进行算术运算的情况下)保持直方图样本不变。在原生直方图成为稳定特征之前,这种行为将转变为有意义的行为。