PromQL是Prometheus内置的数据查询DSL 语言,其提供对时间序列丰富的查询,聚合以及逻辑运算能力的支持。当前,PromQL被广泛应用在Prometheus的日常使用中,包括数据查询、可视化、告警处理等,可以说,掌握PromQL是熟练使用prometheus的必备条件。

前面的文章已经讲解了如何部署Prometheus,本文将通过Prometheus内置的表达式浏览器来演示PromQL语言的使用。


 




Prometheus监控运维实战四: PromQL语法_prometheus


 



一. 基础查询



Prometheus基础查询的一般表达式格式为:<metric name>{label=value},通过指标名称加标签的方式进行查询。

如查看Prometheus更新接口的请求次数,可用如下表达式:



prometheus_http_requests_total{handler="/-/reload"}



在表达式浏览器上执行后,显示出了三个数据,通过标签可看到分别对应code码为200、405和500的请求数。

Prometheus监控运维实战四: PromQL语法_云原生_02

查询表达式也支持通过指标名称(例如http_request_total),或者一个不会匹配到空字符串的标签过滤器 (例如{code="200"}) 来进行查询。



prometheus_http_requests_total   #合法
prometheus_http_requests_total{} #合法
{handler="/api/v1/query"} #合法



PromQL支持使用=和!=两种匹配模式,通过使用label =value 可以查询那些标签满足表达式的时间序列,而与之相反使用label !=value则会排除满足条件的时间序列。

以上面的查询为例,假如我们只想关注非正常响应的请求,可使用下列表达式:

prometheus_http_requests_total{handler="/-/reload",code!="200"}


此时,查询结果会排除code=200的时间序列,并返回其他类型的数据。

Prometheus监控运维实战四: PromQL语法_prometheus_03



除了使用完全匹配的方式的进行查询外,PromQL还支持使用正则表达式作为匹配条件,书写格式为label =~regx,其中~为表示符,regx为正则内容。


例如,通过正则表达式的模糊匹配方式,上述的接口查询也可以使用下列表达式达到相同效果

prometheus_http_requests_total{handler=~".*reload"}


如需要同时查询多个接口的时间序列的话,可使用如下正则表达式

prometheus_http_requests_total{handler=~"/graph|/rules|/metrics"}


 

二. 时间范围查询

在上述的基础查询案例中, 我们通过 <metric name>{label=value} 格式进行查询时,返回结果中只会包含该时间序列的最新一个值,这样的结果类型称为瞬时向量(instant vector )。除了瞬时向量,PromQL也支持返回时间序列在某个时间范围内的一组数据,这种称为范围向量(range vector )。

范围向量表达式需要定义时间选择的范围,时间范围被包含在[]号中。

例如查询5分钟内的样本数据,可用下列表达式

prometheus_http_requests_total{handler="/-/reload",code="200"}[5m]


在Prometheus的表达式浏览器中,我们可以看到,返回的数据包含了5分钟内的所有采样结果

Prometheus监控运维实战四: PromQL语法_监控_04



  除了使用m表示分钟以外,PromQL的时间范围选择器支持其它时间单位:

  • s - 秒
  • m - 分钟
  • h - 小时
  • d - 天
  • w - 周
  • y - 年


 

在时间序列的查询上,除了以当前时间为基准,也可以使用offset进行时间位移的操作。

如以1小时前的时间点为基准,查询瞬时向量和5分钟内的范围向量:

prometheus_http_requests_total{handler="/-/reload",code="200"} offset 1h  
prometheus_http_requests_total{handler="/-/reload",code="200"}[5m] offset 1h


 

三. 操作符


在PromQL的查询中,还可以通过表达式操作符,进行更加复杂的结果查询,常见的操作有下列几种。


数学运算符

数据运算符使用的加、减、乘、除等方式,对样本值进行计算,并返回计算后的结果。

例如,通过process_virtual_memory_bytes获取到的内存值单位为byte,我们希望转换为GB为单位时,只需要使用下列表达式处理

process_virtual_memory_bytes/(1024*1024*1024)


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

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

 

比较运算符

比较运算符支持用户根据时间序列样本的值,对时间序列进行过滤。

例如,我们只想查询Prometheus请求量大于1千的接口数据,则可以使用下列比较表达式进行过滤。

prometheus_http_requests_total{code="200"} > 1000


Prometheus监控运维实战四: PromQL语法_监控_05



比较表达式还可以与bool修饰符进行搭配,添加bool后表达式将不再对数据进行过滤,而是根据比较结果返回1(true)或0(false)。

例如 :

prometheus_http_requests_total{code="200"} > bool 1000


Prometheus监控运维实战四: PromQL语法_监控_06



Prometheus支持的比较运算符如下:


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


 

逻辑运算符

逻辑运算符支持的操作有 and、or、unless(排除)三种,其中and为并集,用于匹配表达式中相同的结果。

如下示例,该表达式将匹配大于100小于1000区间的时间序列样本



prometheus_http_requests_total < 1000 or prometheus_http_requests_total > 100


其中,表达式1为显示所有小于1千的样本,而表达式2则是显示所有大于100的样本,在并集匹配后,将会显示两者间相同的数据,即小于1千大于100这个区间的样本。

Prometheus监控运维实战四: PromQL语法_云原生_07



unless与and正好相反,匹配结果将会排除两者中相同的样本,只显示其中对方互不包含部分的合集;而or的匹配范围最广,它除了会匹配表达式1所有的数据外,还会匹配表达式2中与其不相同的样本。


 


注意:Prometheus 的运算符之间存在着优先级,其中由高到低依次为(^)> (*, /, %) > (+, -) > (==, !=, <=, <, >=, >) > (and, unless) > (or) ,在使用过程中需要注意优先级关系,避免出现错误结果。


 

四. 聚合操作

PromQL语言提供了不少内置的聚合操作符,用于对瞬时向量的样本进行聚合操作 ,形成一个新的序列。目前支持的聚合操作符如下:



  • sum (求和)
  • min (最小值)
  • max (最大值)
  • avg (平均值)
  • stddev (标准差)
  • stdvar (标准方差)
  • count (计数)
  • count_values (对value进行计数)
  • bottomk (后n条时序)
  • topk (前n条时序)
  • quantile (分位数)

聚合操作符有非常多的用途,例如可使用sum对返回结果进行汇总,得到一个总值 。

例如要计算所有接口的请求数量总和,可以用如下表达式:

sum(prometheus_http_requests_total{})


使用max,匹配其中样本值为最大的时间序列

max(prometheus_http_requests_total{})


使用avg,求出所有样本的平均值 

avg(prometheus_http_requests_total{})


使用​​topk​​ ,可显示匹配的前N条时间序列数据

topk (5,prometheus_http_requests_total{})


在聚合操作中,还可以在表达式中加上without或 by ,其中without用于在计算样本中移除列举的标签,而by正相反,结果向量中只保留列出的标签,其余标签则移除。



sum(prometheus_http_requests_total{}) without (code,handler,job) 
sum(prometheus_http_requests_total{}) by (instance)


 

五. 内置函数


Prometheus内置不少函数,通过灵活的应用这些函数,可以更方便的查询及数据格式化。 Promehtues的函数包含了各式各样的功能,本文将选取其中较常使用到的几个函数进行讲解。


ceil 函数

ceil函数会将返回结果的值向上取整数。

示例:

ceil(avg(prometheus_http_requests_total{code="200"}))


floor 函数

floor 函数与ceil相反,将会进行向下取整的操作。

示例:



floor(avg(prometheus_http_requests_total{code="200"}))


rate函数

rate函数是使用频率最高,也是最重要的函数之一。rate用于取某个时间区间内每秒的平均增量数,它会以该时间区间内的所有数据点进行统计。rate函数通常作用于Counter类型的指标,用于了解增量情况。

示例:获取http_request_total在2分钟内,平均每秒新增的请求数



rate(prometheus_http_requests_total{handler="/rules"}[1m])


irate函数

相比rate函数,irate提供了更高的灵敏度。irate函数是通过时间区间中最后两个样本数据来计算区间向量的增长速率,从而避免范围内的平均值拉低峰值的情况。

示例:该函数用法与rate相同



irate(prometheus_http_requests_total{handler="/rules"}[1m])


其它内置函数

除了上面提到的这些函数外,PromQL还提供了大量的其他函数供使用,功能范围涵盖了日常所需的功能,如用于标签替换的label_replace函数、统计Histogram指标分位数的histogram_quantile函数,更多信息可参阅官方文档:https://prometheus.io/docs/prometheus/latest/querying/functions/。