使用 PromQL 除了能够方便的按照查询和过滤时间序列以外,PromQL 还支持丰富的操作符,用户可以使用这些操作符进一步的对事件序列进行二次加工。
这些操作符包括:数学运算符,逻辑运算符,布尔运算符等等。
数学运算符
瞬时向量与标量之间进行数学运算时,数学运算符会依次作用于瞬时向量中的每一个样本值,从而得到一组新的时间序列。
瞬时向量与瞬时向量之间进行数学运算时,数学运算符会依次找到与左边向量元素匹配(标签完全一致)的右边向量元素进行运算,如果没找到匹配元素,则直接丢弃。
PromQL 支持的所有数学运算符如下所示:
布尔运算符
布尔运算支持用户根据时间序列中样本的值,对时间序列进行过滤。
瞬时向量与标量进行布尔运算时,PromQL 依次比较向量中的所有时间序列样本的值,如果比较结果为 true 则保留,反之丢弃。
瞬时向量与瞬时向量直接进行布尔运算时,同样遵循默认的匹配模式:依次找到与左边向量元素匹配(标签完全一致)的右边向量元素进行相应的操作,如果没找到匹配元素,则直接丢弃。
PromQL 支持的布尔运算符如下:
使用 bool 修饰符改变布尔运算符的行为
布尔运算符的默认行为是对时序数据进行过滤,可以使用 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
集合运算符
通过集合运算,可以在两个瞬时向量与瞬时向量之间进行相应的集合操作。
目前,Prometheus支持以下集合运算符:
匹配模式详解
向量与向量之间进行运算操作时会基于默认的匹配规则:依次找到与左边向量元素匹配(标签完全一致)的右边向量元素进行运算,如果没找到匹配元素,则直接丢弃。
在 PromQL 中有两种典型的匹配模式:
多对一(many-to-one)或一对多(one-to-many)
一对一匹配
一对一匹配模式会对操作符两边的瞬时向量依次进行比较并找到唯一匹配(标签完全一致)的样本值。
默认情况下,表达式如下:
vector1 <operator> vector2
在操作符两边表达式标签不一致的情况下,可以使用 on(label list) 或者 ignoring(label list) 来修改便签的匹配行为。
使用 ignoreing 可以在匹配时忽略某些标签
<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
使用 PromQL 表达式:
method_code:http_errors:rate5m{code="500"} / ignoring(code) method:http_requests:rate5m
该表达式会返回在过去 5 分钟内,HTTP 请求状态码为 500 的请求在所有请求中的比例。如果没有使用 ignoring(code),操作符两边表达式返回的瞬时向量中将找不到任何一个标签完全相同的匹配项。
因此结果如下:
{method="get"} 0.04 // 24 / 600
{method="post"} 0.05 // 6 / 120
多对一和一对多匹配
多对一和一对多两种匹配模式指的是 “一” 侧的每一个向量元素可以与 "多" 侧的多个元素匹配的情况。
在这种情况下,必须使用 group 修饰符:group_left 或者 group_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>
示例
存在下列样本:
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 / ignoring(code) group_left method:http_requests:rate5m
在限定匹配标签后,右向量中的元素可能匹配到多个左向量中的元素。因此该表达式的匹配模式为多对一,需要使用 group 修饰符 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