Prometheus学习笔记六—亿文说尽PromQL查询语言

海阔凭鱼跃,天高任鸟飞

Prometheus官网:https://prometheus.io/

1.什么是PromQL?

PromQL是Prometheus的标准查询语句,**Prometheus 通过指标名称(metrics name)以及对应的一组标签(labelset)唯一定义一条时间序列。**指标名称反映了监控样本的基本标识,而 label 则在这个基本特征上为采集到的数据提供了多种特征维度。用户可以基于这些特征维度过滤,聚合,统计从而产生新的计算后的一条时间序列。

Prometheus 提供内置 PromQL 功能查询语言,提供对时间序列数据丰富的查询,聚合以及逻辑运算能力的支持。使用户可以实时选择和汇总时间序列数据。表达式的结果可以显示为图形,可以在 Prometheus 的表达式浏览器中显示为表格数据,也可以由外部系统通过 HTTP API 使用。

在 Prometheus 的表达语言中,一个表达式或子表达式可以计算为以下四种类型之一:
瞬时向量(Instant vector):它是指在同一时刻,抓取所有度量指标数据。这些度量指标数据的key都是相同的,也就是相同的时间戳.
范围向量(Range vector):它是指在任何一个时间范围内,抓取所有度量指标数据.
标量(Scalar):一个简单的数字浮点值。
字符串(String):一个未被使用的简单字符串值.
注意:根据表达式的不同,得出的图像也是有范围性的。例如仪表盘的数据只能显示瞬时向量。

2.PromQL的基本使用

2.1时间序列选择器

什么是时间序列?
通过Node Exporter暴露的HTTP服务,Prometheus可以采集到当前主机所有监控指标的样本数据。例如:

# HELP node_cpu Seconds the cpus spent in each mode.
# TYPE node_cpu counter
node_cpu{
    
    cpu="cpu0",mode="idle"} 362812.7890625
# HELP node_load1 1m load average.
# TYPE node_load1 gauge
node_load1 3.0703125

其中非#开头的每一行表示当前Node Exporter采集到的一个监控样本:node_cpu和node_load1表明了当前指标的名称、大括号中的标签则反映了当前样本的一些特征和维度、浮点数则是该监控样本的具体值。

样本
Prometheus会将所有采集到的样本数据以时间序列(time-series)的方式保存在内存数据库中,并且定时保存到硬盘上。
time-series是按照时间戳和值的序列顺序存放的,我们称之为向量(vector). 每条time-series通过指标名称(metrics name)和一组标签集(labelset)命名。
如下所示,可以将time-series理解为一个以时间为Y轴的数字矩阵:

  ^
  │   . . . . . . . . . . . . . . . . .   . .   node_cpu{
    
    cpu="cpu0",mode="idle"}. . . . . . . . . . . . . . . . . . .   node_cpu{
    
    cpu="cpu0",mode="system"}. . . . . . . . . .   . . . . . . . .   node_load1{
    
    }. . . . . . . . . . . . . . . .   . .  
  v
    <------------------ 时间 ---------------->

在time-series中的每一个点称为一个样本(sample),样本由以下三部分组成:
指标(metric):metric name和描述当前样本特征的labelsets;
时间戳(timestamp):一个精确到毫秒的时间戳;
样本值(value): 一个float64的浮点型数据表示当前样本的值。

<--------------- metric ---------------------><-timestamp -><-value->
http_request_total{
    
    status="200", method="GET"}@1434417560938 => 94355
http_request_total{
    
    status="200", method="GET"}@1434417561287 => 94334

http_request_total{
    
    status="404", method="GET"}@1434417560938 => 38473
http_request_total{
    
    status="404", method="GET"}@1434417561287 => 38544

http_request_total{
    
    status="200", method="POST"}@1434417560938 => 4748
http_request_total{
    
    status="200", method="POST"}@1434417561287 => 4785

指标(Metric)
在形式上,所有的指标(Metric)都通过如下格式标示:

<metric name>{
    
    <label name>=<label value>, ...}

指标的名称(metric name)可以反映被监控样本的含义(比如,http_request_total - 表示当前系统接收到的HTTP请求总量)。指标名称只能由ASCII字符、数字、下划线以及冒号组成并必须符合正则表达式[a-zA-Z_:][a-zA-Z0-9_:]*。

标签(label)反映了当前样本的特征维度,通过这些维度Prometheus可以对样本数据进行过滤,聚合等。标签的名称只能由ASCII字符、数字以及下划线组成并满足正则表达式[a-zA-Z_][a-zA-Z0-9_]*。

其中以__作为前缀的标签,是系统保留的关键字,只能在系统内部使用。标签的值则可以包含任何Unicode编码的字符。在Prometheus的底层实现中指标名称实际上是以__name__=的形式保存在数据库中的,因此以下两种方式均表示的同一条time-series:

api_http_requests_total{
    
    method="POST", handler="/messages"}

等同于:

{
    
    __name__="api_http_requests_total",method="POST", handler="/messages"}

在Prometheus源码中也可以找到指标(Metric)对应的数据结构,如下所示:

type Metric LabelSet

type LabelSet map[LabelName]LabelValue

type LabelName string

type LabelValue string

Metrics类型
在Prometheus的存储实现上所有的监控样本都是以time-series的形式保存在Prometheus内存的TSDB(时序数据库)中,而time-series所对应的监控指标(metric)也是通过labelset进行唯一命名的。

从存储上来讲所有的监控指标metric都是相同的,但是在不同的场景下这些metric又有一些细微的差异。 例如,在Node Exporter返回的样本中指标node_load1反应的是当前系统的负载状态,随着时间的变化这个指标返回的样本数据是在不断变化的。而指标node_cpu所获取到的样本数据却不同,它是一个持续增大的值,因为其反应的是CPU的累积使用时间,从理论上讲只要系统不关机,这个值是会无限变大的。

为了能够帮助用户理解和区分这些不同监控指标之间的差异,Prometheus定义了4种不同的指标类型(metric type):Counter(计数器)、Gauge(仪表盘)、Histogram(直方图)、Summary(摘要)。

在Exporter返回的样本数据中,其注释中也包含了该样本的类型。例如:

# HELP node_cpu Seconds the cpus spent in each mode.
# TYPE node_cpu counter
node_cpu{
    
    cpu="cpu0",mode="idle"} 362812.7890625

Counter:只增不减的计数器
Counter类型的指标其工作方式和计数器一样,只增不减(除非系统发生重置)。常见的监控指标,如http_requests_total,node_cpu都是Counter类型的监控指标。 一般在定义Counter类型指标的名称时推荐使用_total作为后缀。

Counter是一个简单但有强大的工具,例如我们可以在应用程序中记录某些事件发生的次数,通过以时序的形式存储这些数据,我们可以轻松的了解该事件产生速率的变化。 PromQL内置的聚合操作和函数可以让用户对这些数据进行进一步的分析:
例如,通过rate()函数获取HTTP请求量的增长率:

rate(http_requests_total[5m])

查询当前系统中,访问量前10的HTTP地址:

topk(10, http_requests_total)

Gauge:可增可减的仪表盘
与Counter不同,**Gauge类型的指标侧重于反应系统的当前状态。因此这类指标的样本数据可增可减。**常见指标如:node_memory_MemFree(主机当前空闲的内容大小)、node_memory_MemAvailable(可用内存大小)都是Gauge类型的监控指标。

通过Gauge指标,用户可以直接查看系统的当前状态:

node_memory_MemFree

对于Gauge类型的监控指标,通**过PromQL内置函数delta()可以获取样本在一段时间返回内的变化情况。**例如,计算CPU温度在两个小时内的差异:

delta(cpu_temp_celsius{
    
    host="zeus"}[2h])

还可以使用deriv()计算样本的线性回归模型,甚至是直接使用predict_linear()对数据的变化趋势进行预测。例如,预测系统磁盘空间在4个小时之后的剩余情况:

predict_linear(node_filesystem_free{
    
    job="node"}[1h], 4 * 3600)

使用Histogram和Summary分析数据分布情况
除了Counter和Gauge类型的监控指标以外,Prometheus还定义了Histogram和Summary的指标类型。Histogram和Summary主用用于统计和分析样本的分布情况。

在大多数情况下人们都倾向于使用某些量化指标的平均值,例如CPU的平均使用率、页面的平均响应时间。这种方式的问题很明显,以系统API调用的平均响应时间为例:如果大多数API请求都维持在100ms的响应时间范围内,而个别请求的响应时间需要5s,那么就会导致某些WEB页面的响应时间落到中位数的情况,而这种现象被称为长尾问题。

为了区分是平均的慢还是长尾的慢,最简单的方式就是按照请求延迟的范围进行分组。例如,统计延迟在0到10ms之间的请求数有多少而10~20ms之间的请求数又有多少。通过这种方式可以快速分析系统慢的原因。Histogram和Summary都是为了能够解决这样问题的存在,通过Histogram和Summary类型的监控指标,我们可以快速了解监控样本的分布情况。

例如,指标prometheus_tsdb_wal_fsync_duration_seconds的指标类型为Summary。 它记录了Prometheus Server中wal_fsync处理的处理时间,通过访问Prometheus Server的/metrics地址,可以获取到以下监控样本数据:

# HELP prometheus_tsdb_wal_fsync_duration_seconds Duration of WAL fsync.
# TYPE prometheus_tsdb_wal_fsync_duration_seconds summary
prometheus_tsdb_wal_fsync_duration_seconds{
    
    quantile="0.5"} 0.012352463
prometheus_tsdb_wal_fsync_duration_seconds{
    
    quantile="0.9"} 0.014458005
prometheus_tsdb_wal_fsync_duration_seconds{
    
    quantile="0.99"} 0.017316173
prometheus_tsdb_wal_fsync_duration_seconds_sum 2.888716127000002
prometheus_tsdb_wal_fsync_duration_seconds_count 216

从上面的样本中可以得知当前Prometheus Server进行wal_fsync操作的总次数为216次,耗时2.888716127000002s。其中中位数(quantile=0.5)的耗时为0.012352463,9分位数(quantile=0.9)的耗时为0.014458005s。

在Prometheus Server自身返回的样本数据中,我们还能找到类型为Histogram的监控指标prometheus_tsdb_compaction_chunk_range_bucket。

# HELP prometheus_tsdb_compaction_chunk_range Final time range of chunks on their first compaction
# TYPE prometheus_tsdb_compaction_chunk_range histogram
prometheus_tsdb_compaction_chunk_range_bucket{
    
    le="100"} 0
prometheus_tsdb_compaction_chunk_range_bucket{
    
    le="400"} 0
prometheus_tsdb_compaction_chunk_range_bucket{
    
    le="1600"} 0
prometheus_tsdb_compaction_chunk_range_bucket{
    
    le="6400"} 0
prometheus_tsdb_compaction_chunk_range_bucket{
    
    le="25600"} 0
prometheus_tsdb_compaction_chunk_range_bucket{
    
    le="102400"} 0
prometheus_tsdb_compaction_chunk_range_bucket{
    
    le="409600"} 0
prometheus_tsdb_compaction_chunk_range_bucket{
    
    le="1.6384e+06"} 260
prometheus_tsdb_compaction_chunk_range_bucket{
    
    le="6.5536e+06"} 780
prometheus_tsdb_compaction_chunk_range_bucket{
    
    le="2.62144e+07"} 780
prometheus_tsdb_compaction_chunk_range_bucket{
    
    le="+Inf"} 780
prometheus_tsdb_compaction_chunk_range_sum 1.1540798e+09
prometheus_tsdb_compaction_chunk_range_count 780

与Summary类型的指标相似之处在于Histogram类型的样本同样会反应当前指标的记录的总数(以_count作为后缀)以及其值的总量(以_sum作为后缀)。不同在于Histogram指标直接反应了在不同区间内样本的个数,区间通过标签len进行定义。

同时对于Histogram的指标,我们还可以**通过histogram_quantile()函数计算出其值的分位数。**不同在于Histogram通过histogram_quantile函数是在服务器端计算的分位数。 而Sumamry的分位数则是直接在客户端计算完成。因此对于分位数的计算而言,Summary在通过PromQL进行查询时有更好的性能表现,而Histogram则会消耗更多的资源。反之对于客户端而言Histogram消耗的资源更少。在选择这两种方式时用户应该按照自己的实际场景进行选择。

2.1.1 瞬时向量选择器

瞬时向量选择器允许在给定的时间戳上选这一组时间序列和每个样本的单个采样值,返回值只会包含该时间序列中的最新的一个样本值。
当我们直接使用监控指标名称查询时,可以查询包含该 metric 名称的所有时间序列。以下两种表达方式是等同的:

prometheus_http_requests_total
prometheus_http_requests_total{
    
    }

该表达式会返回指标名称为 prometheus_http_requests_total 的所有时间序列。
在这里插入图片描述
通过在花括号 {} 中添加逗号分隔的标签匹配器列表,可以进一步过滤这些时间序列。

如果我们只需要查询所有 prometheus_http_requests_total 时间序列中满足标签 job 为 prometheus 且 group 为 canary 的时间序列,可以使用如下表达式。

prometheus_http_requests_total{
    
    job="prometheus",group="canary"}

PromQL 还支持用户根据时间序列的标签匹配模式来对时间序列进行过滤,目前主要支持两种匹配模式:完全匹配和正则匹配。

通过使用 label=value 可以选择那些标签满足表达式定义的时间序列
反之使用 label!=value 则可以根据标签匹配排除时间序列
使用 label=~regx 表示选择那些标签符合正则表达式定义的时间序列
反之使用 label!~regx 进行排除
多个表达式之间使用 | 进行分离

例如,如果我们只需要查询所有prometheus_http_requests_total时间序列中满足标签instance为localhost:9090的时间序列,则可以使用如下表达式:

prometheus_http_requests_total{
    
    instance="localhost:9090"}

反之使用instance!="localhost:9090"则可以排除这些时间序列:

prometheus_http_requests_total{
    
    instance!="localhost:9090"}

例如,如果想查询多个环节下的时间序列序列可以使用如下表达式:

prometheus_http_requests_total{
    
    environment=~"staging|testing|development",method!="GET"}

在标签匹配中如果指定标签值为空,会匹配所有不包含该标签的时间序列,同一标签名称可有多个匹配器。
向量选择器必须指定一个名称或至少一个 与空字符串不匹配的标签匹配器。

以下表达式是非法的,

{
    
    job=~".*"}

相反,这些表达式是有效的,因为它们都有一个与空标签值不匹配的选择器。

{
    
    job=~".+"}
{
    
    job=~".*",method="get"}

标签匹配还以使用内部的 name 标签应用到 metric 名称,如 prometheus_http_requests_total 等同于{ name=”prometheus_http_requests_total”},

下面的表达式会筛选出所有以 job:开头的 metric,

{
    
    __name__=~"job:.*"}

另外 metric 名称不能包含以下关键字:bool,on,ignoring,group_left 和 group_right 可使用如下方式代替,

{
    
    __name__="on"}

Prometheus 中的所有正则表达式都使用 RE2 syntax.
RE2 syntax:
https://github.com/google/re2/wiki/Syntax

2.2 区间向量选择器

2.2.1 范围向量选择器

直接通过类似于PromQL表达式prometheus_http_requests_total查询时间序列时,返回值中只会包含该时间序列中的最新的一个样本值,这样的返回结果我们称之为瞬时向量,这样的表达式称为瞬时向量表达式。

如果想查过去时间范围内的样本数据时,就需要使用区间向量表达式。区间向量表达式和瞬间向量表达式之间的差异在于 在区间向量表达式中需要定义时间选择的范围,时间范围通过时间选择器 [] 进行定义。

时间范围选择器内容指定为数字,紧随其后的是以下单位之一:

s – seconds 秒
m – minutes 分钟
h – hours 小时
d – days 天
w – weeks 周
y – years 年

例如,如通过以下表达式可以选择最近 5 分钟内的所有样本数据:

http_requests_total{
    
    }[5m]

该表达式将会返回查询到的时间序列中最近5分钟的所有样本数据,通过区间向量表达式查询到的结果称为区间向量。

2.2.2 时间位移操作

在瞬时向量表达式或者区间向量表达式中,都是以当前时间为基准。

http_request_total{
    
    } # 瞬时向量表达式,选择当前最新的数据
http_request_total{
    
    }[5m] # 区间向量表达式,选择以当前时间为基准,5分钟内的数据

而如果我们想查询,5 分钟前的瞬时样本数据,或昨天一天的区间内的样本数据呢?这个时候我们就可以使用位移操作,可以使用 offset 时间位移操作:

http_request_total{
    
    } offset 5m
http_request_total{
    
    }[1d] offset 1d

需要注意的是 offset 关键词需要紧跟在选择器之后。

sum(http_requests_total{
    
    method="GET"} offset 5m) // 正确
sum(http_requests_total{
    
    method="GET"}) offset 5m // 错误

2.2.3 使用聚合操作

如果描述样本特征的标签(label)在并非唯一的情况下,通过PromQL查询数据,会返回多条满足这些特征维度的时间序列。而PromQL提供的聚合操作可以用来对这些时间序列进行处理,形成一条新的时间序列:
支持的聚合操作符:

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)。

# 查询系统所有http请求的总量
sum(http_request_total)

# 按照mode计算主机CPU的平均使用时间
avg(node_cpu) by (mode)

# 按照主机查询各个主机的CPU使用率
sum(sum(irate(node_cpu{
    
    mode!='idle'}[5m]))  / sum(irate(node_cpu[5m]))) by (instance)

PrmoQL 提供了内置的聚合操作符,包括 sum、min、max、avg、group、count ,etc等等。

#表达方
<aggr-op> [without|by (<label list>)] ([parameter,] <vector expression>)<aggr-op>([parameter,] <vector expression>) [without|by (<label list>)]

without 会从结果向量中删除列出的标签,而所有其他标签将保留输出。by 会执行相反的操作并删除 by 子句中未列出的标签,paramer 仅在使用 count_values,quantile,topk 和 bottomk,需要指定。

#例如:
sum without (instance) (http_requests_total) // HTTP requests per application and group
sum by (application, group) (http_requests_total) //同上
#如果只需要计算整个应用的HTTP请求总量,可以直接使用表达式:
sum(http_requests_total)

count_values用于时间序列中每一个样本值出现的次数。
count_values会为每一个唯一的样本值输出一个时间序列,并且每一个时间序列包含一个额外的标签。

#例如:
count_values("count", http_requests_total)

topk和bottomk则用于对样本值进行排序,返回当前样本值前n位,或者后n位的时间序列。
获取HTTP请求数前5位的时序样本数据,可以使用表达式:

topk(5, http_requests_total)

quantile用于计算当前样本数据值的分布情况quantile(φ, express)其中0 ≤ φ ≤ 1。
例如,当φ为0.5时,即表示找到当前样本数据中的中位数:

quantile(0.5, http_requests_total)

2.3 标量和字符串

除了使用瞬时向量表达式和区间向量表达式以外,PromQL还直接支持用户使用标量(Scalar)和字符串(String)。

标量(Scalar):一个浮点型的数字值
标量只有一个数字,没有时序。

10

需要注意的是,当使用表达式count(http_requests_total),返回的数据类型,依然是瞬时向量。用户可以通过内置函数scalar()将单个瞬时向量转换为标量。

字符串(String):一个简单的字符串值
直接使用字符串,作为PromQL表达式,则会直接返回字符串。

"this is a string"
'these are unescaped: \n \\ \t'
`these are not unescaped: \n ' " \t`

合法的PromQL表达式标准:
所有的PromQL表达式都必须至少包含一个指标名称(例如http_request_total),或者一个不会匹配到空字符串的标签过滤器(例如{code=“200”})。

因此以下两种方式,均为合法的表达式:

http_request_total # 合法
http_request_total{
    
    } # 合法
{
    
    method="get"} # 合法

而如下表达式,则不合法:

{
    
    job=~".*"} # 不合法

3.PromQL操作符

PromQL支持丰富的操作符:数字运算符,逻辑运算符,布尔运算符等等。

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

node_memory_free_bytes_total / (1024 * 1024)

node_memory_free_bytes_total表达式会查询出所有满足表达式条件的时间序列,称表达式为瞬时向量表达式,而返回的结果成为瞬时向量。
当瞬时向量与标量之间进行数学运算时,数学运算符会依次作用域瞬时向量中的每一个样本值,从而得到一组新的时间序列。

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

node_disk_bytes_written + node_disk_bytes_read

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

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

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

使用布尔运算过滤时间序列
在PromQL通过标签匹配模式,用户可以根据时间序列的特征维度对其进行查询。而布尔运算则支持用户根据时间序列中样本的值,对时间序列进行过滤。
例如,通过数学运算符我们可以很方便的计算出,当前所有主机节点的内存使用率:

(node_memory_MemTotal_bytes - node_memory_MemFree_bytes) / node_memory_MemTotal_bytes

而系统管理员在排查问题的时候可能只想知道当前内存使用率超过95%的主机呢?通过使用布尔运算符可以方便的获取到该结果:

(node_memory_MemTotal_bytes - node_memory_MemFree_bytes) / node_memory_MemTotal_bytes > 0.95

瞬时向量与标量进行布尔运算时,PromQL依次比较向量中的所有时间序列样本的值,如果比较结果为true则保留,反之丢弃。
瞬时向量与瞬时向量直接进行布尔运算时,同样遵循默认的匹配模式:依次找到与左边向量元素匹配(标签完全一致)的右边向量元素进行相应的操作,如果没找到匹配元素,则直接丢弃。

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

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

使用bool修饰符改变布尔运算符的行为
布尔运算符的默认行为是对时序数据进行过滤。,而在其它的情况下我们可能需要的是真正的布尔结果。
例如,只需要知道当前模块的HTTP请求量是否>=1000,如果大于等于1000则返回1(true)否则返回0(false)。这时可以使用bool修饰符改变布尔运算的默认行为。 例如:

http_requests_total > bool 1000

使用bool修改符后,布尔运算不会对时间序列进行过滤,而是直接依次判断瞬时向量中的各个样本数据与标量的比较结果0或者1。从而形成一条新的时间序列。

{
    
    code="200",handler="/metrics",instance="localhost:9090",job="prometheus"}	1
{
    
    code="200",handler="/graph",instance="localhost:9090",job="prometheus"}	0

同时需要注意的是,如果是在两个标量之间使用布尔运算,则必须使用bool修饰符

2 == bool 2 # 结果为1

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

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

1.vector1 and vector2 会产生一个由vector1的元素组成的新的向量。该向量包含vector1中完全匹配vector2中的元素组成。
2.vector1 or vector2 会产生一个新的向量,该向量包含vector1中所有的样本数据,以及vector2中没有与vector1匹配到的样本数据。
3.vector1 unless vector2 会产生一个新的向量,新向量中的元素 由vector1中没有与vector2匹配的元素组成。

操作符优先级
对于复杂类型的表达式,需要了解运算操作的运行优先级
例如,查询主机的CPU使用率,可以使用表达式:

100 * (1 - avg (irate(node_cpu{
    
    mode='idle'}[5m])) by(job) )
100 * (1 - avg (irate(node_cpu_seconds_total{
    
    mode='idle'}[5m])) by(job) )

其中irate是PromQL中的内置函数,用于计算区间向量中时间序列每秒的即时增长率。
在PromQL操作符中优先级由高到低依次为:

^
*, /, %
+, -
==, !=, <=, <, >=, >
and, unless
or

匹配模式
向量与向量之间进行运算操作时会基于默认的匹配规则:依次找到与左边向量元素匹配(标签完全一致)的右边向量元素进行运算,如果没找到匹配元素,则直接丢弃。
PromQL中有两种典型的匹配模式:一对一(one-to-one),多对一(many-to-one)或一对多(one-to-many)。

一对一匹配
一对一匹配模式会从操作符两边表达式中获取的瞬时向量依次比较并找到唯一匹配(标签完全一致)的样本值。默认情况下,使用表达式:

vector1 <operator> vector2

在操作符两边表达式标签不一致的情况下,可以使用on(label list)或者ignoring(label list)来修改便签的匹配行为。
1.使用ignoreing可以在匹配时忽略某些便签。
2.on则用于将匹配行为限定在某些便签之内。

<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

同时由于method为put和del的样本找不到匹配项,因此不会出现在结果当中。

多对一和一对多
对一和一对多两种匹配模式指的是“一”侧的每一个向量元素可以与"多"侧的多个元素匹配的情况。
这种情况下,必须使用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>

多对一和一对多两种模式一定是出现在操作符两侧表达式返回的向量标签不一致的情况。因此需要使用ignoring和on修饰符来排除或者限定匹配的标签列表。
例如,使用表达式:

method_code:http_errors:rate5m / ignoring(code) group_left method:http_requests:rate5m

该表达式中,左向量method_code:http_errors:rate5m包含两个标签method和code。而右向量method:http_requests:rate5m中只包含一个标签method,因此匹配时需要使用ignoring限定匹配的标签为code。 在限定匹配标签后,右向量中的元素可能匹配到多个左向量中的元素 因此该表达式的匹配模式为多对一,需要使用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

提醒:group修饰符只能在比较和数学运算符中使用。在逻辑运算and,unless和or才注意操作中默认与右向量中的所有元素进行匹配。

4.内置常用函数

计算Counter指标增长率
increase(v range-vector)函数是PromQL中提供的众多内置函数之一。
其中参数v是一个区间向量,increase函数获取区间向量中的第一个后最后一个样本并返回其增长量。因此,可以通过以下表达式Counter类型指标的增长率:

increase(node_cpu[2m]) / 120

这里通过node_cpu[2m]获取时间序列最近两分钟的所有样本,increase计算出最近两分钟的增长量,最后除以时间120秒得到node_cpu样本在最近两分钟的平均增长率。并且这个值也近似于主机节点最近两分钟内的平均CPU使用率。

rate(v range-vector)函数,rate函数可以直接计算区间向量v在时间窗口内平均增长速率。因此,通过以下表达式可以得到与increase函数相同的结果:

rate(node_cpu[2m])

注意使用rate或者increase函数去计算样本的平均增长速率,容易陷入“长尾问题”当中,其无法反应在时间窗口内样本数据的突发变化。
例如,对于主机而言在2分钟的时间窗口内,可能在某一个由于访问量或者其它问题导致CPU占用100%的情况,但是通过计算在时间窗口内的平均增长率却无法反应出该问题。

irate(v range-vector)函数,irate同样用于计算区间向量的计算率,但是其反应出的是瞬时增长率。irate函数是通过区间向量中最后两个样本数据来计算区间向量的增长速率。
这种方式可以避免在时间窗口范围内的“长尾问题”,并且体现出更好的灵敏度,通过irate函数绘制的图标能够更好的反应样本数据的瞬时变化状态。

irate(node_cpu[2m])

irate函数相比于rate函数提供了更高的灵敏度,不过当需要分析长期趋势或者在告警规则中,irate的这种灵敏度反而容易造成干扰。因此在长期趋势分析或者告警中更推荐使用rate函数。

predict_linear(v range-vector, t scalar) 函数可以处理一些管理员无法及时处理的问题情况。predict_linear 可用于 gauges 类型数据,predict_linear 函数可以预测时间序列 v 在 t 秒后的值,它基于简单线性回归的方式,对时间窗口内的样本数据进行统计,从而可以对时间序列的变化趋势做出预测。

例如,基于2小时的样本数据,来预测主机可用磁盘空间的是否在4个小时候被占满,可以使用如下表达式:

predict_linear(node_filesystem_free{
    
    job="node"}[2h], 4 * 3600) < 0

当资源占用不是平滑变化的使用 predict_linear 可以做到提前预警,可以有效避免基于资源用量是平滑增长的的阈值告警模式出现的告警还未来的及处理系统就不可用的情况。

Summary函数是直接在客户端计算了数据分布的分位数情况。
Histogram函数分位数计算需要通过histogram_quantile(φ float, b instant-vector)函数进行计算。
其中φ(0<φ<1)表示需要计算的分位数,如果需要计算中位数φ取值为0.5,以此类推即可

以指标http_request_duration_seconds_bucket为例:

# HELP http_request_duration_seconds request duration histogram
# TYPE http_request_duration_seconds histogram
http_request_duration_seconds_bucket{
    
    le="0.5"} 0
http_request_duration_seconds_bucket{
    
    le="1"} 1
http_request_duration_seconds_bucket{
    
    le="2"} 2
http_request_duration_seconds_bucket{
    
    le="3"} 3
http_request_duration_seconds_bucket{
    
    le="5"} 3
http_request_duration_seconds_bucket{
    
    le="+Inf"} 3
http_request_duration_seconds_sum 6
http_request_duration_seconds_count 3

当计算9分位数时,使用如下表达式:

histogram_quantile(0.5, http_request_duration_seconds_bucket)

通过对Histogram类型的监控指标,用户可以轻松获取样本数据的分布情况。同时分位数的计算,也可以非常方便的用于评判当前监控指标的服务水平。
需要注意的是通过histogram_quantile计算的分位数,并非为精确值,而是通过http_request_duration_seconds_bucket和http_request_duration_seconds_sum近似计算的结果。

动态标签替换
一般来说来说,使用PromQL查询到时间序列后,可视化工具会根据时间序列的标签来渲染图表。例如通过up指标可以获取到当前所有运行的Exporter实例以及其状态:

up{
    
    instance="localhost:8080",job="cadvisor"}    1
up{
    
    instance="localhost:9090",job="prometheus"}    1
up{
    
    instance="localhost:9100",job="node"}    1

这是可视化工具渲染图标时可能根据,instance和job的值进行渲染,为了能够让客户端的图标更具有可读性,可以通过label_replace标签为时间序列添加额外的标签。
label_replace的具体参数如下:

label_replace(v instant-vector, dst_label string, replacement string, src_label string, regex string)

label_replace该函数会依次对v中的每一条时间序列进行处理,通过regex匹配src_label的值,并将匹配部分relacement写入到dst_label标签中。

label_replace(up, "host", "$1", "instance",  "(.*):.*")

函数处理后,时间序列将包含一个host标签,host标签的值为Exporter实例的IP地址:

up{
    
    host="localhost",instance="localhost:8080",job="cadvisor"}    1
up{
    
    host="localhost",instance="localhost:9090",job="prometheus"}    1
up{
    
    host="localhost",instance="localhost:9100",job="node"} 1

label_join该函数可以将时间序列中v多个标签src_label的值,通过separator作为连接符写入到一个新的标签dst_label中。

label_join(v instant-vector, dst_label string, separator string, src_label_1 string, src_label_2 string, ...)

label_replace和label_join函数提供了对时间序列标签的自定义能力,从而能够更好的于客户端或者可视化工具配合。
其他内置函数查看Prometheus的官方文档,了解这些函数的使用方式。

abs(v instant-vector)函数:将瞬时值转换为绝对值
absent(v instant-vector)函数:如果传递给它的向量有任何元素,则返回一个空向量;如果传递给它的向量没有元素,则返回一个值为1的元素向量。 这对于在给定度量名称和标签组合不存在时间序列时发出警报非常有用。

#例如:
absent(nonexistent{
    
    job="myjob"})
absent(sum(nonexistent{
    
    job="myjob"}))

ceil(v instant-vector)函数:是一个向上舍入为最接近的整数
floor(v instant-vector)函数:与ceil()函数相反。
changes()函数:对于每个输入时间序列,changes作为即时向量返回其值在给定时间范围内更改的次数。

#例如:
#查看十分钟内总内存的变化。应该得到0
changes(node_memory_MemTotal_bytes{
    
    instance="xx.xx.xx.xx:9100"}[10m])
#查看十分钟服务器进程总数的变化次数
changes(node_procs_running{
    
    instance="xx.xx.xx.xx:9100"} [10m])

clamp_max()函数:函数,输入一个瞬时向量和最大值,样本数据值若大于max,则改为max,否则不变。
clamp_min()函数:输入一个瞬时向量和最大值,样本数据值小于min,则改为min,否则不变。
**day_of_month()函数:**返回被给定UTC时间所在月的第几天。返回值范围:1~31
**day_of_week()函数:**返回被给定UTC时间所在周的第几天。返回值范围:0~6
**days_in_month()函数:**函数,返回当月一共有多少天。返回值范围:28~31
**delta()函数:**计算一个范围向量v的第一个元素和最后一个元素之间的差值。返回值:key:value=
度量指标:差值 查询过去10小时的cpu_load变化

**deriv()函数:**计算一个范围向量v中各个时间序列二阶导数,使用简单线性回归
**exp()函数:**入一个瞬时向量, 返回各个样本值的e指数值,即为 e^N次方
holt_winters()函数:函数基于区间向量 v,生成时间序列数据平滑值。平滑因子sf越低, 对旧数据的重视程度越高。趋势因子tf越高,对数据的趋势的考虑就越多。其中: 0< sf, tf <=1` holt_winters 仅适用于 Gauge 类型的时间序列
**hour()函数:**函数返回被给定 UTC 时间的当前第几个小时,时间范围:0~23
**idelta()函数:**输入一个范围向量,返回key: value = 度量指标:每最后两个样本值差值。
increase()函数:输入一个范围向量,返回:key:value = 度量指标:last值-first值,自动调整单调性,如:服务实例重启,则计数器重置。与delta()不同之处在于delta是求差值,而increase返回最后一个减第一个值,可 为正为负
**label_join()函数:**可以将时间序列 v 中多个标签src_label的值,通过 separator 作为连接符写入到一个新的标签dst_label中。可以有多个src_label标签。
ln()函数:计算瞬时向量 v 中所有样本数据的自然对数。
log2()函数:函数计算瞬时向量 v 中所有样本数据的二进制对数。
log10()函数:计算瞬时向量 v 中所有样本数据的十进制对数。
minute()函数:函数返回给定 UTC 时间当前小时的第多少分钟。结果范围:0~59。
month()函数: 函数返回给定 UTC 时间当前属于第几个月,结果范围:0~12
resets()函数:resets(v range-vector)的参数是一个区间向量。对于每个时间序列,它都返回一个计数器重置的次数。两个连续样本之间的值的减少被认为是一次计数器重置。这个函数一般只用在计数器类型的时间序列上。
round()函数:round(v instant-vector, to_nearest=1 scalar)函数与ceil和floor函数类似,返回向量中所有样本值的最接近的整数。to_nearest 参数是可选的,默认为 1,表示样本返回的是最接近 1 的整数倍的值。你也可以将该参数指定为任意值(也可以是小数),表示样本返回的是最接近它的整数倍的值。
scalar()函数:scalar(v instant-vector)函数的参数是一个单元素的瞬时向量,它返回其唯一的时间序列的值作为一个标量。如果度量指标的样本数量大于 1 或者等于 0, 则返回 NaN。
sort()函数:sort(v instant-vector)函数对向量按元素的值进行升序排序,返回结果:key: value = 度量指标:样本值[升序排列]。
sort_desc()函数:sort(v instant-vector)函数对向量按元素的值进行降序排序,返回结果:key: value = 度量指标:样本值[降序排列]。
sqrt()函数:sqrt(v instant-vector)函数计算向量 v 中所有元素的平方根。
time()函数:函数返回从 1970-01-01 到现在的秒数。注意:它不是直接返回当前时间,而是时间戳
timestamp()函数:timestamp(v instant-vector)函数返回向量 v 中的每个样本的时间戳(从 1970-01-01 到现在的秒数)。
vector()函数:函数将标量 s 作为没有标签的向量返回,即返回结果为:key: value= {}, s。
year()函数:year(v=vector(time()) instant-vector)函数返回被给定 UTC 时间的当前年份。
_over_time()函数:下面的函数列表允许传入一个区间向量,它们会聚合每个时间序列的范围,并返回一个瞬时向量:

avg_over_time(range-vector) : 区间向量内每个度量指标的平均值。
min_over_time(range-vector) : 区间向量内每个度量指标的最小值。
max_over_time(range-vector) : 区间向量内每个度量指标的最大值。
sum_over_time(range-vector) : 区间向量内每个度量指标的求和。
count_over_time(range-vector) : 区间向量内每个度量指标的样本数据个数。
quantile_over_time(scalar, range-vector) : 区间向量内每个度量指标的样本数据值分位数,φ-quantile (0 ≤ φ ≤ 1)。
stddev_over_time(range-vector) : 区间向量内每个度量指标的总体标准差。
stdvar_over_time(range-vector) : 区间向量内每个度量指标的总体标准方差。

即使区间向量内的值分布不均匀,它们在聚合时的权重也是相同的。
更多查看Prometheus官网:https://prometheus.io/docs/prometheus/latest/querying/functions/

5.HTTP API操作PromQL

API响应格式
Prometheus API使用了JSON格式的响应内容。 当API调用成功后将会返回2xx的HTTP状态码。
反之,当API调用失败时可能返回以下几种不同的HTTP状态码:

404 Bad Request:当参数错误或者缺失时。
422 Unprocessable Entity 当表达式无法执行时。
503Service Unavailiable 当请求超时或者被中断时。

所有的API请求均使用以下的JSON格式:

{
    
    
  "status": "success" | "error",
  "data": <data>,

  // Only set if status is "error". The data field may still hold
  // additional data.
  "errorType": "<string>",
  "error": "<string>"
}

在HTTP API中使用PromQL
通过HTTP API我们可以分别通过/api/v1/query和/api/v1/query_range查询PromQL表达式当前或者一定时间范围内的计算结果。
瞬时数据查询
通过使用QUERY API我们可以查询PromQL在特定时间点下的计算结果。

GET /api/v1/query

URL请求参数:

query=:PromQL表达式。
time=:用于指定用于计算PromQL的时间戳。可选参数,默认情况下使用当前系统时间。
timeout=:超时设置。可选参数,默认情况下使用-query,timeout的全局设置。

例如使用以下表达式查询表达式up在时间点2015-07-01T20:10:51.781Z的计算结果:

$ curl 'http://localhost:9090/api/v1/query?query=up&time=2015-07-01T20:10:51.781Z'
{
    
    
   "status" : "success",
   "data" : {
    
    
      "resultType" : "vector",
      "result" : [
         {
    
    
            "metric" : {
    
    
               "__name__" : "up",
               "job" : "prometheus",
               "instance" : "localhost:9090"
            },
            "value": [ 1435781451.781, "1" ]
         },
         {
    
    
            "metric" : {
    
    
               "__name__" : "up",
               "job" : "node",
               "instance" : "localhost:9100"
            },
            "value" : [ 1435781451.781, "0" ]
         }
      ]
   }
}

响应数据类型
当API调用成功后,Prometheus会返回JSON格式的响应内容,格式如上小节所示。并且在data节点中返回查询结果。data节点格式如下:

{
    
    
  "resultType": "matrix" | "vector" | "scalar" | "string",
  "result": <value>
}

PromQL表达式可能返回多种数据类型,在响应内容中使用resultType表示当前返回的数据类型,包括:

瞬时向量:vector

当返回数据类型resultType为vector时,result响应格式如下:

[
  {
    
    
    "metric": {
    
     "<label_name>": "<label_value>", ... },
    "value": [ <unix_time>, "<sample_value>" ]
  },
  ...
]

其中metrics表示当前时间序列的特征维度,value只包含一个唯一的样本。

区间向量:matrix

当返回数据类型resultType为matrix时,result响应格式如下:

[
  {
    
    
    "metric": {
    
     "<label_name>": "<label_value>", ... },
    "values": [ [ <unix_time>, "<sample_value>" ], ... ]
  },
  ...
]

其中metrics表示当前时间序列的特征维度,values包含当前事件序列的一组样本。

标量:scalar

当返回数据类型resultType为scalar时,result响应格式如下:

[ <unix_time>, "<scalar_value>" ]

由于标量不存在时间序列一说,因此result表示为当前系统时间一个标量的值。

字符串:string

当返回数据类型resultType为string时,result响应格式如下:

[ <unix_time>, "<string_value>" ]

字符串类型的响应内容格式和标量相同。

区间数据查询
使用QUERY_RANGE API我们则可以直接查询PromQL表达式在一段时间返回内的计算结果。

GET /api/v1/query_range

URL请求参数:

query=: PromQL表达式。
start=: 起始时间。
end=: 结束时间。
step=: 查询步长。
timeout=:超时设置。可选参数,默认情况下使用-query,timeout的全局设置。

当使用QUERY_RANGE API查询PromQL表达式时,返回结果一定是一个区间向量:

{
    
    
  "resultType": "matrix",
  "result": <value>
}

需要注意的是,在QUERY_RANGE API中PromQL只能使用瞬时向量选择器类型的表达式。
例如使用以下表达式查询表达式up在30秒范围内以15秒为间隔计算PromQL表达式的结果。

$ curl 'http://localhost:9090/api/v1/query_range?query=up&start=2015-07-01T20:10:30.781Z&end=2015-07-01T20:11:00.781Z&step=15s'
{
    
    
   "status" : "success",
   "data" : {
    
    
      "resultType" : "matrix",
      "result" : [
         {
    
    
            "metric" : {
    
    
               "__name__" : "up",
               "job" : "prometheus",
               "instance" : "localhost:9090"
            },
            "values" : [
               [ 1435781430.781, "1" ],
               [ 1435781445.781, "1" ],
               [ 1435781460.781, "1" ]
            ]
         },
         {
    
    
            "metric" : {
    
    
               "__name__" : "up",
               "job" : "node",
               "instance" : "localhost:9091"
            },
            "values" : [
               [ 1435781430.781, "0" ],
               [ 1435781445.781, "0" ],
               [ 1435781460.781, "1" ]
            ]
         }
      ]
   }
}

6.使用建议

4个黄金指标和USE方法
在这里插入图片描述
4个黄金指标
Four Golden Signals是Google针对大量分布式监控的经验总结,4个黄金指标可以在服务级别帮助衡量终端用户体验、服务中断、业务影响等层面的问题。主要关注与以下四种类型的指标:延迟,通讯量,错误以及饱和度:

延迟:服务请求所需时间。
记录用户所有请求所需的时间,重点是要区分成功请求的延迟时间和失败请求的延迟时间。 例如在数据库或者其他关键祸端服务异常触发HTTP 500的情况下,用户也可能会很快得到请求失败的响应内容,如果不加区分计算这些请求的延迟,可能导致计算结果与实际结果产生巨大的差异。除此以外,在微服务中通常提倡“快速失败”,开发人员需要特别注意这些延迟较大的错误,因为这些缓慢的错误会明显影响系统的性能,因此追踪这些错误的延迟也是非常重要的。

通讯量:监控当前系统的流量,用于衡量服务的容量需求。
流量对于不同类型的系统而言可能代表不同的含义。例如,在HTTP REST API中, 流量通常是每秒HTTP请求数;

错误:监控当前系统所有发生的错误请求,衡量当前系统错误发生的速率。
对于失败而言有些是显式的(比如, HTTP 500错误),而有些是隐式(比如,HTTP响应200,但实际业务流程依然是失败的)。

对于一些显式的错误如HTTP 500可以通过在负载均衡器(如Nginx)上进行捕获,而对于一些系统内部的异常,则可能需要直接从服务中添加钩子统计并进行获取。

饱和度:衡量当前服务的饱和度。
主要强调最能影响服务状态的受限制的资源。 例如,如果系统主要受内存影响,那就主要关注系统的内存状态,如果系统主要受限与磁盘I/O,那就主要观测磁盘I/O的状态。因为通常情况下,当这些资源达到饱和后,服务的性能会明显下降。同时还可以利用饱和度对系统做出预测,比如,“磁盘是否可能在4个小时候就满了”。

RED方法
RED方法是Weave Cloud在基于Google的“4个黄金指标”的原则下结合Prometheus以及Kubernetes容器实践,细化和总结的方法论,特别适合于云原生应用以及微服务架构应用的监控和度量。主要关注以下三种关键指标:
(请求)速率:服务每秒接收的请求数。
(请求)错误:每秒失败的请求数。
(请求)耗时:每个请求的耗时。

在“4大黄金信号”的原则下,RED方法可以有效的帮助用户衡量云原生以及微服务应用下的用户体验问题。

USE方法
USE方法全称"Utilization Saturation and Errors Method",主要用于分析系统性能问题,可以指导用户快速识别资源瓶颈以及错误的方法。正如USE方法的名字所表示的含义,USE方法主要关注与资源的:使用率(Utilization)、饱和度(Saturation)以及错误(Errors)。

**使用率:**关注系统资源的使用情况。 这里的资源主要包括但不限于:CPU,内存,网络,磁盘等等。100%的使用率通常是系统性能瓶颈的标志。
**饱和度:**例如CPU的平均运行排队长度,这里主要是针对资源的饱和度(注意,不同于4大黄金信号)。任何资源在某种程度上的饱和都可能导致系统性能的下降。
**错误:**错误计数。例如:“网卡在数据包传输过程中检测到的以太网网络冲突了14次”。
通过对资源以上指标持续观察,通过以下流程可以知道用户识别资源瓶颈:
在这里插入图片描述
聚合操作符的使用顺序
1.先使用 sum 再使用 rate,原因是在服务器重启的情况下 counter 会被置 0,如果先使用 sum 再使用 rate,重启现象会被掩盖,从而会出现假峰值,其它类似的操作符和函数还有 min,max,avg,ceil,histogram_quantile,predict_linear etc。
2.可直接安全的作用与 counter 的操作符有 rate,irate,increase,resets 其它都需要慎重考虑引起的其它问题。

避免慢查询和数据过载
1.当数据量很大时,对其直接进行查询或绘图时很有可能导致服务器或浏览器过载或超时,合理的做法是指定合理的时间范围和查询步长,可以在 Prometheus 自带的查询界面构建查询表达式增加标签进行筛选或聚合,直到获得一个合理的查询结果集。
2.当使用以上方式仍不能完全缓解查询压力,可以通过 Recording Rules 保存常用的查询数据以提高查询效率。
Recording Rules:https://prometheus.io/docs/prometheus/latest/configuration/recording_rules/#recording-rules

时间范围和数据拉取间隔
时间范围通常大于等于 4 倍数据拉取时间间隔,举例:当数据拉取间隔为 10s, rate 或 irate 至少需要两个样本点,所以需要 30s 来保证至少覆盖两个时间点,考虑到某个时间点拉取出错,所以 40s 是一个较为合理的时间范围,实际使用通常取整到 1m 举例:

irate(http_requests_total{
    
    job=”api-server”}[1m])

1.对于 irate 指定一个大的时间范围没有意义的,通常指定为四倍数据拉取时间间隔
2.对于 rate 没有明确的建议,需要考虑的是时间范围越大,会拉平出现的数据峰值,获得更为平缓的速率

irate 和 rate 和查询步长
1.当调用 /api/v1/query_range 获取绘图数据时,需要指定参数 query 查询范围,指定获取时间序列样本量的大小,step 查询步长,查询步长决定了绘图点的个数,步长越小绘图点越多,考虑到图的直观及可读性需要选择合适的步长。

2.irate 适合快速变化的计数器, 当查询步长大于 irate 时间范围时,由于其只取最后两个数据点,可能会导致在时间范围外的数据峰值点未能被捕获,查询步长与其时间范围越接近, 会捕获更多的数据峰值,曲线变化也更灵敏精确,推荐在重要且需要监测其细节变化的 metric 中使用。

3.大多数情况下我们可以使用 rate,但需要注意的是时间范围不应当小于步长,否则可能会漏掉数据。

参考文献
https://yunlzheng.gitbook.io/prometheus-book/parti-prometheus-ji-chu/promql/prometheus-promql-operators-v2
https://opensource.actionsky.com/20200825-prometheus/
https://www.shangyexinzhi.com/article/257869.html

猜你喜欢

转载自blog.csdn.net/ZhanBiaoChina/article/details/109012566