PromQL详解(二)
PromQL详解(二)
操作符¶
聚合操作符¶
Prometheus 为使用者提供了内置的聚合操作符,这些操作符仅仅适用于单个瞬时向量进行聚合操作。聚合操作可以将瞬时向量聚合后生成一个包含较少元素的新的时间序列。
聚合操作的语法: [操作符(sum或者max)] ([参数,n] <向量表达式>) [without|by(标签列表)]
对于支持参数的聚合操作有 count_value bottomk topk quantile
| 名称 | 描述 | 
|---|---|
| sum | 求和,最常用的聚合操作符,将组中所有的值相加,并将其作为组的值返回。 | 
| max | 最大值,将组内的最大值作为组的值的值返回。 | 
| min | 最小值,与最大值得计算规则相同。 | 
| avg | 平均值,返回组中时间序列值的平均值作为组的值。 | 
| stddev | 标准差,对一组数字分布情况的统计度量,用于检测异常值。 | 
| stdvar | 标准方差,标准差的平方,用来做统计 | 
| bottomk | 用于对样本值进行排序,返回当前样本值 后 N位的时间序列。 | 
| topk | 和 bottomk正好相反,返回当前样本值 前N位的时间序列。 | 
| count | 计数, 计算组中的时间序列数,并将其作为组的值返回。 | 
| count_value | 对相同的value进行计数,用于统计时间序列中每一个样本值出现的次数。 count_value会为每一个唯一的样本值输出一个时间序列,并且每一个时间序列都包含一个额外的标签。这个标签的名字由聚合参数指定,同时这个标签值是唯一的样本值 | 
| quantile | 
例子:
sum(apiserver_request_total) without (instance) 
等同于
sum(apiserver_request_total) by (group,namespace)
语法 中的 without 可以把列出来的标签从计算结果里删除,未在列表中的标签则保留输出结果中。 by 正好与 without 执行操作相反,只将存在列表中的标签保留在输出结果中,删除其余未在 by 字句列表中的标签。
对于简单的统计,直接可以只用表达式:
sum(apiserver_request_total) 计算当前所有应用程序中的code的api请求总量。
运算符¶
当我们需要使用不同的监控指标进行更多操作的时候,PromQL 聚合操作就会出现无法满足当前的使用情况。这时候,Prometheus提供的多种运算符就派上了用场。这些运算符不仅仅允许对瞬时向量进行简单的算术运算,同时还可以将运算符
应用于俩个基于标签分组的瞬时向量。我们现在开始详细的讲讲 算术运算符 关系运算符 向量匹配 和 逻辑运算符
- 算术运算符
Prometheus中所提供的算术运算大部分的工作原理基本相同,有编程功底的同学,可以看到其语义表达的与大部分编程语言中的语义基本相同。
| 运算符 | 描述 | 
|---|---|
| + | 相加 | 
| - | 相减 | 
| * | 相乘 | 
| / | 相除 | 
| % | 求余 | 
| ^ | 幂运算 | 
支持的运算符数据之间的操作分为三类:
- 标量 [scalar]↔ 标量[scalar]
例子: 在PromQL中 使用 (7+8)*3 查询,会返回结果 45 左边就是我们看到的元素是标量 scalar 类型,右边是数值 45,其所返回的结果也是标量。
- 瞬时向量 [vector]↔ 标量[scalar]
瞬时向量与标量之间运算时,算术运算符会依次作用于瞬时向量中一个样本值,从而得到一组新的时间序列。
例子:
我们使用监控指标 node_memory_MemTotal_bytes 获取当前node节点的内存总空间大小, 单位为 bytes,我们需要换算为MB,表达式为:
node_memory_MemTotal_bytes / (1024 * 1024) 此时的返回一组元素结果,这里的 node_memory_MemTotal_bytes 为瞬时向量,(1024 * 1024) 为标量。
- 瞬时向量 [vector]↔ 瞬时向量[vector]
瞬时向量与瞬时向量的算术运算的过程相对复杂度略高。
例子:
比如我们使用 node_disk_read_bytes_total 与 node_disk_written_bytes_total 来计算当前磁盘读写时间总量,表达式为:
node_disk_read_bytes_total + node_disk_written_bytes_total
上面的表达式工作过程中,是依次找到与左边 向量元素 匹配(标签精确匹配)的右边向量元素进行运算,如果找到匹配元素,直接丢弃,新的时间序列将不会包含该指标名称。
node_disk_read_bytes_total{device=~"sda"} + node_disk_written_bytes_total
上面的表达式中的向量元素中的标签已经写成 device=~"sda" ,因此,只会显示匹配到的 device=~"sda"的 向量元素,然后返回瞬时向量的时间序列。
node_disk_read_bytes_total{instance='k8s-m1'} + node_disk_written_bytes_total
上面的表达式面这个的指标 instance='k8s-m1' ,因此他只会显示匹配当前指定标签的时间序列。
- 关系运算符
Prometheus 也有关系运算符,也叫比较运算符,理解起来是比较容易的。
| 关系运算符 | 描述 | 
|---|---|
| == | 相等 | 
| != | 不相等 | 
| > | 大于 | 
| < | 小于 | 
| >= | 大于等于 | 
| <= | 小于等于 | 
关系运算符与算术运算符数据之间的操作一样分为三类:
- 
标量 [scalar]↔ 标量[scalar]
- 
瞬时向量 [vector]↔ 标量[scalar]
- 
瞬时向量 [vector]↔ 瞬时向量[vector]
只不过关系运算符默认情况下,用于对时序数据进行过滤。但是有些情况下,可以通过在运算符之后使用
bool修饰符,从而不对时间序列进行过滤,直接返回 0 false 或者 1 true。
例子1:在俩个标量之间进行关系运算,必须使用bool修饰符,并且这些运算符会产生另一个标量,即 0 false 或者 1  true。
在PromeQL中使用 77 >= bool 55 查询的时候,返回的元素是 scalar 样本值是 1 true,如果关系运算符调整为 <=,返回结果则是 0 false
例子2:瞬时向量与标量之间进行关系运算的时候,这个运算符会应用到某个当前时间的每一个时间序列上,如果一个时间序列数据值与这个标量的比较结果是 false。
则这个时间序列数据被丢弃,如果发 true,则这个时间序列数据被保留在结果中。比如,我们使用监控指标 node_netstat_Tcp_CurrEstab 获取当前node节点的网络状态为
ESTABLISHED,数量大于200的表达式为:
node_netstat_Tcp_CurrEstab >= 200  此时会返回一个瞬时向量,后续我们如果需要监控当前网络状态的报警设置阈值的时候可以使用当前这个表达式。
例子3:瞬时向量与瞬时向量之间进行关系运算时,运算符默认情况下是过滤的,用于匹配条目。表达式不是 true 或在表达式的另一侧找不到匹配项的向量元素将被从结果中删除,
不在结果中显示。否则将保留在左侧的度量指标和标签的样本数据写入瞬时向量。如果提供了bool修饰符,则删除的向量元素值为 0,而保留的向量元素为 1,左侧标签值为 1。  
node_netstat_Tcp_InSegs <= node_netstat_Tcp_OutSegs
node_netstat_Tcp_InSegs <= bool node_netstat_Tcp_OutSegs
node_netstat_Tcp_InSegs >= bool node_netstat_Tcp_OutSegs