PromQL是Prometheus内置的数据查询语言,其提供对时间序列数据丰富的查询,聚合以及逻辑运算能力的支持。并且被广泛应用在Prometheus的日常应用当中,包括对数据查询、可视化、告警处理当中,下面我们讲简单了解一下PromQL语言,并且从简单的例子入手。数据类型 在Prometheus的表达式语言中,任何表达式或者子表达式都可以归为四种类型:1.instant vector 瞬时向量 :一组时间序列,包含每个时间序列的单个样本,所有时间序列都共享相同的时间戳。2.range vector 范围向量 :一组时间序列,包含每个时间序列随时间变化的一系列数据点。
3.scalar 标量 :一个简单的浮点值
4.string 字符串 :一个当前没有被使用的简单字符串操作符

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

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

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

 

 

举例说明↓↓↓

例如我们查询主机的内存大小,返回的是Bytes,如果我要把他转换成G可以使用一下表达式:node_memory_MemTotal_bytes / 1024 /1024 /1024返回的结果是一个瞬时向量。两个瞬时向量之间的数学计算例如:node_disk_written_bytes_total + node_disk_read_bytes_total 那么我们会发现是根据表达式的标签进行数学运算,分别算出vda、vdb的磁盘io。Prometheus支持以下布尔运算符如下:
== (相等)!= (不相等)> (大于)< (小于)>= (大于等于)<= (小于等于)
使用bool修饰符、返回匹配的查询结果↓↓↓例如:通过数学运算符我们可以很方便的计算出,当前所有主机节点的内存使用率:(node_memory_bytes_total - node_memory_free_bytes_total) / node_memory_bytes_total而在我们写告警规则的时候我们需要筛选出,内存使用率超过百分之95的主机、则可以使用布尔运算表达式:(node_memory_bytes_total - node_memory_free_bytes_total) / node_memory_bytes_total > 0.95Prometheus 支持以下集合运算符:

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

通过集合运算,可以在两个瞬时向量与瞬时向量之间进行相应的集合操作↓↓↓

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

 

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

 

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

优先级 在 Prometheus 系统中,二元运算符优先级从高到低的顺序为:
^*, /, %+, -==, !=, <=, <, >=, >and, unlessor
具有相同优先级的运算符是满足结合律的(左结合)。例如,2 3 % 2 等价于 (2 3) % 2。运算符 ^ 例外,^ 满足的是右结合,例如,2 ^ 3 ^ 2 等价于 2 ^ (3 ^ 2)。聚合运算 Prometheus还提供了下列内置的聚合操作符,这些操作符作用于瞬时向量。可以将瞬时表达式返回的样本数据进行聚合,形成一个新的时间序列。
   sum (求和)   min (最小值)   max (最大值)   avg (平均值)   stddev (标准差)   stdvar (标准差异)   count (计数)   count_values (对value进行计数)   bottomk (后n条时序)   topk (前n条时序)   quantile (分布统计)

 

使用聚合操作的语法如下:<aggr-op>([parameter,] <vector expression>) [without|by (<label list>)]其中只有count_values, quantile, topk, bottomk支持参数(parameter)。without用于从计算结果中移除列举的标签,而保留其它标签。by则正好相反,结果向量中只保留列出的标签,其余标签则移除。通过without和by可以按照样本的问题对数据进行聚合。sum(http_requests_total) without (instance)等于:sum(http_requests_t;otal) by (code,handler,job,method)如果只需要计算整个应用的HTTP请求总量,可以直接使用表达式:sum(http_requests_total)查询数据的平均值:avg(http_requests_total)查询最靠前的3个值:topk(3, http_requests_total)常用函数 Prometheus为不同的数据类型提供了非常多的计算函数,有个小技巧就是遇到counter数据类型,在做任何操作之前,先套上一个rate()或者increase()函数。下面介绍一些比较常用的函数帮助理解:increase()函数:该函数配合counter数据类型使用,获取区间向量中的第一个和最后一个样本并返回其增长量。如果除以一定时间就可以获取该时间内的平均增长率:
  •  
increase(node_cpu_seconds_total[2m]) / 120 #主机节点最近两分钟内的平均CPU使用率
rate()函数:该函数配合counter类型数据使用,取counter在这个时间段中的平均每秒增量。
  •  
rate(node_cpu_seconds_total[2m]) #直接计算区间向量在时间窗口内平均增长速率
sum()函数:在实际工作中CPU大多是多核的,而node_cpu会将每个核的数据都单独显示出来,我们其实不会关注每个核的单独情况,而是关心总的CPU情况。使用sum()函数进行求和后可以得出一条总的数据,但sum()是将所有机器的数据都进行了求和,所以还要再使用by (instance)或者by (cluster_name)就可以取出单个服务器或者一组服务器的CPU数据。上面的公式可以进化为:
  •  
sum( increase(node_cpu_seconds_total[1m]) ) #先找出每一个,然后再合并
Topk()函数:该函数可以从大量数据中取出排行前N的数值,N可以自定义。比如监控了100台服务器的320个CPU,用这个函数就可以查看当前负载较高的那几个,用于报警:
  •  
topk(3, http_requests_total) #统计最靠前的3个值
predict_linear()函数:对曲线变化速率进行计算,起到一定的预测作用。比如当前这1个小时的磁盘可用率急剧下降,这种情况可能导致磁盘很快被写满,这时可以使用该函数,用当前1小时的数据去预测未来几个小时的状态,实现提前告警:
  •  
predict_linear( node_filesystem_free_bytes{mountpoint="/"}[1h],4*3600 ) < 0 #如果未来4小时后磁盘使用率为负数就会报警
CPU利用率表达式拆解 1.先把key找出来,比如是为了查看CPU的使用率,那么就应该使用:
  •  
node_cpu这个key
2.在node_cpu这个key的基础上把idle的CPU时间和全部CPU时间过滤出来,使用{}做过滤:
  •  
node_cpu_seconds_total{ mode='idle' }  #找出空闲CPU的值node_cpu_seconds_total  #不写其他参数代表ALL
3.使用increase()函数把1分钟的数据抓取出来,这个时候取出来的是每个CPU的数据:
  •  
increase(node_cpu_seconds_totalmode='idle'}[1m])
4.使用sum()函数求和每个CPU的数据,得到单独一个数据:
  •  
sum( increase(node_cpu_seconds_total{mode='idle'}[1m]) )
5.sum()函数虽然把每个CPU的数据进行了求和,但是还把每台服务器也进行了求和,所有服务器的CPU数据都相同了,还需要进行一次处理。这里又引出了一个新函数 by (instance)。它会把sum求和到一起的数值按照指定方式进行拆分,instance代表的是机器名。如果不写by (instance)的话就需要在{}中写明需要哪个实例的数据。
  •  
sum( increase(node_cpu_seconds_total{mode='idle'}[1m]) ) by (instance) #空闲CPU一分钟增量
6.获取CPU空闲时间占比:
  •  
sum(increase(node_cpu_seconds_total{mode="idle"}[1m])) by(instance) /sum(increase(node_cpu_seconds_total[1m])) by(instance)
7.CPU的利用率:
  •  
1-(sum(increase(node_cpu_seconds_total{mode="idle"}[1m])) by(instance) /sum(increase(node_cpu_seconds_total[1m])) by(instance)) * 100
最终计算可能为负数,可能好多granafa模板都这样,当cpu处于多核、低负载的情况下,值的差异会被放大,从而导致出现负数的情况。
谁说运维是一块砖?提升运维工作价值一起学习《Devops之监控神器Prometheus》