使用PromQL除了能够方便的按照查询和过滤时间序列以外,PromQL还支持丰富的操作符(Operators),用户可以使用这些操作符对进一步的对事件序列进行二次加工。操作符包括二元操作符和聚合操作符,其中二元操作符包括:数学运算符,逻辑运算符,布尔运算符等, 本节主要介绍二元操作符。
关于operator详细说明,可参考官方文档: https://prometheus.io/docs/prometheus/latest/querying/operators/
PromQL支持的所有数学运算符如下所示:
+
(加法)-
(减法)*
(乘法)/
(除法)%
(求余)^
(幂运算)支持以下三种形式的运算:
例如,我们可以通过指标node_memory_MemFree_bytes
获取当前主机可用的内存空间大小,其样本单位为Bytes。这是如果客户端要求使用MB作为单位响应数据,那只需要将查询到的时间序列的样本值进行单位换算即可:
node_memory_MemFree_bytes / (1024 * 1024)
node_memory_MemFree_bytes
表达式会查询出所有满足表达式条件的时间序列,在上一小节中我们称该表达式为瞬时向量表达式,而返回的结果成为瞬时向量(Instant Vector)。
当瞬时向量与标量之间进行数学运算时,数学运算符会依次作用域瞬时向量中的每一个样本值,从而得到一组新的时间序列:
而如果是瞬时向量与瞬时向量之间进行数学运算时,过程会相对复杂一点。 例如,如果我们想根据node_disk_written_bytes_total
和node_disk_read_bytes_total
获取主机磁盘IO的总量,可以使用如下表达式:
node_disk_written_bytes_total + node_disk_read_bytes_total
那这个表达式是如何工作的呢?依次找到与左边向量元素匹配(标签完全一致)的右边向量元素进行运算,如果没找到匹配元素,则直接丢弃。同时新的时间序列将不会包含指标名称。 该表达式返回结果的示例如下所示:
在PromQL通过标签匹配模式,用户可以根据时间序列的特征维度对其进行查询。而布尔运算则支持用户根据时间序列中样本的值,对时间序列进行过滤。
目前,Prometheus支持以下布尔运算符如下:
==
(相等)!=
(不相等)>
(大于)<
(小于)>=
(大于等于)<=
(小于等于)例如,通过数学运算符我们可以很方便的计算出,当前CPU时间大于10s的结果:
例如检查内存使用率大于90%的机器,通过使用布尔运算符可以方便的获取到该结果,所以布尔运算符经常用于alert manager:
(node_memory_bytes_total - node_memory_free_bytes_total) / node_memory_bytes_total > 0.9
瞬时向量与标量进行布尔运算时,PromQL依次比较向量中的所有时间序列样本的值,如果比较结果为true则保留,反之丢弃。
瞬时向量与瞬时向量直接进行布尔运算时,同样遵循默认的匹配模式:依次找到与左边向量元素匹配(标签完全一致)的右边向量元素进行相应的操作,如果没找到匹配元素,则直接丢弃。
布尔运算符的默认行为是对时序数据进行过滤。而在其它的情况下我们可能需要的是真正的布尔结果。例如,只需要知道当前模块的HTTP请求量是否>=1000,如果大于等于1000则返回1(true)否则返回0(false)。这时可以使用bool修饰符改变布尔运算的默认行为。 例如:
http_requests_total > bool 1000
使用bool修改符后,布尔运算不会对时间序列进行过滤,而是直接依次瞬时向量中的各个样本数据与标量的比较结果0或者1。从而形成一条新的时间序列。
http_requests_total{code="200",handler="query",instance="localhost:9090",job="prometheus",method="get"} 1
http_requests_total{code="200",handler="query_range",instance="localhost:9090",job="prometheus",method="get"} 0
同时需要注意的是,如果是在两个标量之间使用布尔运算,则必须使用bool修饰符
2 == bool 2 # 结果为1
使用瞬时向量表达式能够获取到一个包含多个时间序列的集合,我们称为瞬时向量。 通过集合运算,可以在两个瞬时向量与瞬时向量之间进行相应的集合操作。目前,Prometheus支持以下集合运算符:
and
(并且)or
(或者)unless
(排除)Logical operators
只支持两个瞬时向量之间的操作。
vector1 and vector2 会产生一个由vector1的元素组成的新的向量。该向量包含vector1中完全匹配vector2中的元素组成:
vector1 or vector2 会产生一个新的向量,该向量包含vector1中所有的样本数据,以及vector2中没有与vector1匹配到的样本数据。
vector1 unless vector2 会产生一个新的向量,新向量中的元素由vector1中没有与vector2匹配的元素组成。