二元操作符

使用PromQL除了能够方便的按照查询和过滤时间序列以外,PromQL还支持丰富的操作符(Operators),用户可以使用这些操作符对进一步的对事件序列进行二次加工。操作符包括二元操作符和聚合操作符,其中二元操作符包括:数学运算符,逻辑运算符,布尔运算符等, 本节主要介绍二元操作符。

image-20210503190907238

关于operator详细说明,可参考官方文档: https://prometheus.io/docs/prometheus/latest/querying/operators/

数学运算

PromQL支持的所有数学运算符如下所示:

  • + (加法)
  • - (减法)
  • * (乘法)
  • / (除法)
  • % (求余)
  • ^ (幂运算)

支持以下三种形式的运算:

  • scalar/scalar
  • Vector/scalar
  • vector/vector

例如,我们可以通过指标node_memory_MemFree_bytes获取当前主机可用的内存空间大小,其样本单位为Bytes。这是如果客户端要求使用MB作为单位响应数据,那只需要将查询到的时间序列的样本值进行单位换算即可:

node_memory_MemFree_bytes / (1024 * 1024)

image-20210503191422358 node_memory_MemFree_bytes表达式会查询出所有满足表达式条件的时间序列,在上一小节中我们称该表达式为瞬时向量表达式,而返回的结果成为瞬时向量(Instant Vector)。

当瞬时向量与标量之间进行数学运算时,数学运算符会依次作用域瞬时向量中的每一个样本值,从而得到一组新的时间序列:

image-20210503191613450

而如果是瞬时向量与瞬时向量之间进行数学运算时,过程会相对复杂一点。 例如,如果我们想根据node_disk_written_bytes_totalnode_disk_read_bytes_total获取主机磁盘IO的总量,可以使用如下表达式:

node_disk_written_bytes_total + node_disk_read_bytes_total

那这个表达式是如何工作的呢?依次找到与左边向量元素匹配(标签完全一致)的右边向量元素进行运算,如果没找到匹配元素,则直接丢弃。同时新的时间序列将不会包含指标名称。 该表达式返回结果的示例如下所示:

image-20210503192015801 image-20210503192049522 image-20210503191950549

使用布尔运算过滤时间序列

在PromQL通过标签匹配模式,用户可以根据时间序列的特征维度对其进行查询。而布尔运算则支持用户根据时间序列中样本的值,对时间序列进行过滤。

目前,Prometheus支持以下布尔运算符如下:

  • == (相等)
  • != (不相等)
  • > (大于)
  • < (小于)
  • >= (大于等于)
  • <= (小于等于)

例如,通过数学运算符我们可以很方便的计算出,当前CPU时间大于10s的结果:

image-20210503192319944 image-20210503192340790 例如检查内存使用率大于90%的机器,通过使用布尔运算符可以方便的获取到该结果,所以布尔运算符经常用于alert manager:

(node_memory_bytes_total - node_memory_free_bytes_total) / node_memory_bytes_total > 0.9

瞬时向量与标量进行布尔运算时,PromQL依次比较向量中的所有时间序列样本的值,如果比较结果为true则保留,反之丢弃。

瞬时向量与瞬时向量直接进行布尔运算时,同样遵循默认的匹配模式:依次找到与左边向量元素匹配(标签完全一致)的右边向量元素进行相应的操作,如果没找到匹配元素,则直接丢弃。

使用bool修饰符改变布尔运算符的行为

布尔运算符的默认行为是对时序数据进行过滤。而在其它的情况下我们可能需要的是真正的布尔结果。例如,只需要知道当前模块的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

image-20210503192752538

使用集合运算符

使用瞬时向量表达式能够获取到一个包含多个时间序列的集合,我们称为瞬时向量。 通过集合运算,可以在两个瞬时向量与瞬时向量之间进行相应的集合操作。目前,Prometheus支持以下集合运算符:

  • and (并且)
  • or (或者)
  • unless (排除)

Logical operators只支持两个瞬时向量之间的操作。

vector1 and vector2 会产生一个由vector1的元素组成的新的向量。该向量包含vector1中完全匹配vector2中的元素组成:

image-20210503193458734 vector1 or vector2 会产生一个新的向量,该向量包含vector1中所有的样本数据,以及vector2中没有与vector1匹配到的样本数据。

vector1 unless vector2 会产生一个新的向量,新向量中的元素由vector1中没有与vector2匹配的元素组成。