共计 9845 个字符,预计需要花费 25 分钟才能阅读完成。
一、背景
在 prometheus
中存在各种工夫序列数据,那么咱们如何依据工夫序列查问想要的数据呢?prometheus 为咱们提供了弱小的 PromQL
,借助PromQL
咱们能够查问到本人想要的数据。
二、PromQL 的数据类型
- Instant vector(即时向量):一组工夫序列,每个工夫序列蕴含一个样本,所有样本共享雷同的工夫戳。
- Range vector(范畴向量):一组工夫序列,其中蕴含每个工夫序列随工夫变动的一系列数据点。
- Scalar(标量):一个浮点型的数据值。
- String(字符串):一个字符串,以后没有应用到。
留神:
1、如果咱们要绘制图形,那么必须返回Instant vector
类型的数据。
三、字面量
1、字符串字面量
字符串能够应用 ”(单引号),””(双引号),\`\`(反引号)来示意。在单引号和双引号中,反斜杠成为了转义字符,前面能够跟着 a,b, f, n, r, t, v 或者 \。
eg:
“this is a string”
‘these are unescaped: \n \ \t’these are not unescaped: \n ' " \t
2、浮点数字面量
浮点数能够写成以下这种格局
[-+]?(
[0-9]*.?[0-9]+(eE?[0-9]+)?
| 0xX+
| nN[nN]
| iI[fF]
)
eg:
23
-2.43
3.4e-9
0x8f
-Inf
NaN
四、工夫序列选择器
1、即时向量选择器
即时向量选择器容许在给定的工夫戳(即时)上抉择一组工夫序列和每个样本的单个样本值。
1、组成部分
- 指标名称:用于限定特定指标下的工夫序列,可选。
- 匹配器:用于过滤工夫序列上的标签,可选。定义在
{}
中。
2、指标名称和匹配器的组合
1、只给定指标名称,或者在指标名称上指定空匹配器,这将返回给定指标下的所有工夫序列的即时样本数据。
eg:
up 等价于 up{}
2、只给定匹配器,返回合乎该匹配器的所有工夫序列的即时样本。
eg:
{instance=~”.*”, job=”prometheus”}
3、同时指定指标名称和匹配器,返回合乎给定指标名称和匹配器的即时样本。
eg:
up{job=”prometheus”}
留神:
1、指标名称
和匹配器
必须要抉择一个。
3、匹配器
匹配器次要是用于标签过滤,目前反对如下 4 种格局。
=
: 准确的匹配给定的标签值!=
: 不匹配给定的标签值=~
: 正则表达式匹配给定的标签值!~
: 不匹配正则表格局给定的标签值
eg:
1、查问出指标名称 up
中标签 job
等于 prometheus
的工夫序列数据
up{job=”prometheus”}
2、查问出指标名称 up
中标签 job
不等于 prometheus
的工夫序列数据
up{job!=”prometheus”}
3、查问出指标名称 up
中标签 job
以pro
结尾的的工夫序列数据
up{job=~”pro.*”}
4、查问出指标名称 up
中标签 job
不以 pro
结尾的的工夫序列数据
up{job!~”pro.*”}
5、查问出指标名称 up
中不存在标签 env
的工夫序列数据
up{env=””}
5、查问指标名称是以 prometheus
结尾的所有的工夫序列数据
{__name__ =~”prometheus.*”}
留神:
=~
和!=
必须要指定一个标签名字或者匹配的标签必须要有值。eg:
{job=~””} 或者 {job=~”.*”} 都是错的。{job=”.+”}是正确的。- 上方的正则表达式应用的语法是 RE2 语法
2、区间向量选择器
区间向量选择器和即时向量选择器大抵相似,惟一的不同在于表达式之后须要跟一个 []
表白须要返回那个区间范畴的工夫序列数据。
up[5m]
示意查问 5 分钟工夫内各实例的状态
1、工夫格局
ms(毫秒)、s(秒)、m(分钟)、h(小时)、d(天)、w(周)、y(年)
d
示意一天总是 24 小时 w
示意一周总是 7 天 y
示意一年总是 365 天
能够将多个不同的工夫单位串联起来应用,然而大的工夫单位必须在后面,小的工夫单位在前面,且不同的工夫单位只能呈现一次。且不能是小数。
eg: 1h30m 能够,然而 1.5h 则不才能够。
3、偏移量修改器
默认状况下,即时向量和区间向量选择器都是以以后工夫为准,然而偏移量修改器 offset
能够批改该基准。偏移量选择器是紧跟在表达式之后应用 offset 来指定的。
eg:
1、示意获取指标名称 prometheus_http_requests_total 的所有工夫序列在过来 1 分钟的即时样本。
prometheus_http_requests_total offset 1m
2、示意获取指标名称 prometheus_http_requests_total 的所有工夫序列在间隔此刻 1 分钟之前的 5 分钟之内的样本。
prometheus_http_requests_total[5m] offset 1m
五、运算符
Prometheus
的查询语言反对根本的逻辑和算术运算符。
1、算术运算符
反对的算术运算符:
+(加)、-(减)、*(乘)、/(除)、%(取模)、^(幂等)
二元运算操作符能够在 scalar/scalar(标量 / 标量)、vector/scalar(向量 / 标量)、和 vector/vector(向量 / 向量)之间运算。
- 在两个标量之间运算:失去的后果也是一个标量。
- 在即时向量和标量之间运算:将运算符利用于这个向量中的每个数据样本的值。eg: 如果工夫序列即时向量乘以 2,则后果是另外一个向量,另外一个向量中的值是原始向量的每个样本值乘以 2。
- 在两个即时向量之间运算:运算符会顺次找到与右边向量元素匹配(标签完全一致)的左边向量元素进行运算,如果没找到匹配元素,则间接抛弃。同时新的工夫序列将不会蕴含指标名称。
2、比拟运算符
反对的比拟运算符:
== (等于)、!=(不等于)、>(大于)、<(小于)、>=(大于或等于)、<=(小于或等于)
比拟二元运算符被利用于 scalar/scalar(标量 / 标量)、vector/scalar(向量 / 标量),和 vector/vector(向量 / 向量)之间。比拟运算符失去的后果是 bool 布尔类型值,返回 1 或者 0 值。
-
两个标量之间 d 额布尔运算:必须要提供一个 bool 修饰符,运算的后果会产生一个新的标量,值为 0(假)或 1(真)。
-
即时向量和标量之间的布尔运算:时序数列中的每个值都会与这个运算符进行运算。
- 存在
bool
修饰符:比拟的后果为 0 和 1,指标名称会被删除。 - 不存在
bool
修饰符:如果比拟的后果为 false, 则这个时序数据会被删除, 后果为 true 的保留。
- 存在
- 即时量与即时量间接进行布尔运算时,默认状况下,这些运算符的行为相似于过滤器,利用于匹配的条目。
表达式为 false 或在表达式的另一侧未找到匹配项的向量元素将从后果中删除,而其余元素将流传到后果向量中,分组标签将成为输入标签集。
如果提供了 bool 修饰符,则将被删除的向量元素的值为 0,而将被保留的向量元素的值为 1,
分组标签将再次成为输入标签集。如果提供了 bool 修饰符,则会删除指标名称。
3、汇合运算符
汇合运算符只反对在 2 个即时变量之间的运算。
反对的汇合运算符:
and(并且 - 交加)、or(或者 - 并集)、unless(除非 - 补集)
vector1 and vector2: 会产生一个由 vector1
的元素组成的新的向量。该向量蕴含 vector1 中齐全匹配 vector2
中的元素组成。其它的元素会被删除,指标名称和值从左侧即 vector1
继承。
vector1 or vector2:生成的向量蕴含 vector1
中所有的原始数据 (标签 + 值),以及vector2
在vector1
中没有匹配到的数据。
vector1 unless vector2:后果产生一个新的向量,新向量中的元素由 vector1
中没有与 vector2
匹配的元素组成。匹配到的元素都会被删除。
4、运算符的优先级
运算符优先级从高到低顺次为:
^
*、/、%
+、-
==、!=、<=、<、>=、>
and、unless
or
留神:
优先级雷同的运算符,顺次从左往右进行运算,然而 ^
是从右开始的。
eg:
2 3 4 等价于 (2 3) 4
2 ^ 3 ^ 4 等价于 2 ^ (3 ^ 4)
5、向量匹配
向量之间的运算尝试为左侧的每个条目在右侧向量中找到匹配的元素。
匹配行为有两种根本类型:一对一
和 一对多
或多对一
。
1、基础知识
1、向量之间的匹配是在 2 个即时向量之间进行匹配,不能是区间向量。
2、那么 2 个向量如何算匹配上呢?
这个就须要 2 个向量存在 完全一致的标签值
雷同。比方:2 个向量都存在标签{code="200"}
完全一致的标签值:
1、2 个向量具备完全相同的标签。
2、应用 on
或 ignoring
后具备雷同的标签。
那如果 2 个向量就是标签不同,然而存在若干个雷同的标签,那么怎么比拟呢?
应用 on
指定应用那个标签雷同,就认为匹配上。
应用 ignoring
疏忽某些标签雷同,就认为匹配上。
3、找不到匹配的值会被疏忽,不会呈现在比拟的后果中。
2、示例数据
示例数据是从 prometheus 官网上抄的。
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
1、一对一
一对一从操作的每一侧查找一对惟一的条目。如果两个条目具备完全相同的标签集和相应的值,则它们匹配。
ignoring
:容许在匹配时疏忽某些标签。
on
:容许在匹配时只匹配指定的标签。
1、语法格局
<vector expr> <bin-op> ignoring(<label list>) <vector expr>
<vector expr> <bin-op> on(<label list>) <vector expr>
2、示例
1、查问语句:
method_code:http_errors:rate5m{code="500"} / ignoring(code) method:http_requests:rate5m
2、解释:
1、method_code:http_errors:rate5m{code=”500″}能够查问出如下数据
method_code:http_errors:rate5m{method="get", code="500"} 24
method_code:http_errors:rate5m{method="post", code="500"} 6
2、method:http_requests:rate5m 能够查问出如下数据
method:http_requests:rate5m{method="get"} 600
method:http_requests:rate5m{method="del"} 34
method:http_requests:rate5m{method="post"} 120
3、ignoring(code)的作用
因为 method_code:http_errors:rate5m 比 method:http_requests:rate5m 多了
一个 code
的标签,失常匹配匹配不上,如果疏忽 code 标签的匹配,那么那边的标签一样且标签的值也一样,所有就能够匹配上。
4、比拟的后果
{method="get"} 0.04 // 24 / 600
==> method_code:http_errors:rate5m{method="get", code="500"} / method:http_requests:rate5m{method="get"}
{method="post"} 0.05 // 6 / 120
==> method_code:http_errors:rate5m{method="post", code="500"} / method:http_requests:rate5m{method="post"}
只有 2 边都能匹配上的数据才会呈现。method 等于 put 和 del 的样本找不到匹配项,所以没有呈现在后果集中。
5、为什么没有呈现 method=del 和 method=put 的数据
因为 {method=”del”} 在 method_code:http_errors:rate5m 中没有查问进去,所以在后果中疏忽了。即没有在 2 边都存在并且相匹配上。
2、一对多或多对一
一对多和多对一匹配指的是:“一”的一侧的每个向量元素能够与“多”侧的多个元素进行匹配。必须应用 group_left
或group_right
修饰符显式申请,其中 left/right 确定哪个向量具备更高的基数。
1、语法格局
<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>
2、示例
1、查问语句:
method_code:http_errors:rate5m / ignoring(code) group_left method:http_requests:rate5m
2、解释:
1、ignoring(code) 示意比拟的时候,疏忽 code 标签。
2、group_left 示意,左侧即 method_code:http_errors:rate5m 为 多
的一侧,右侧为 一
的一侧。
3、没有匹配的间接从后果集中删除。
4、后果如下:
{method="get", code="500"} 0.04 // 24 / 600
==> method_code:http_errors:rate5m{method="get", code="500"} / method:http_requests:rate5m{method="get"}
{method="get", code="404"} 0.05 // 30 / 600
==> method_code:http_errors:rate5m{method="get", code="404"} / method:http_requests:rate5m{method="get"}
{method="post", code="500"} 0.05 // 6 / 120
==> ...
{method="post", code="404"} 0.175 // 21 / 120
==> ...
留神:
group
修饰符只能在比拟和数学运算符中应用。在逻辑运算 and
,unless
和 or
操作中默认与右向量中的所有元素进行匹配。
6、聚合操作
Prometheus 提供了如下内置的聚合操作符,这些操作符作用于即时向量。
sum
(求和)min
(求最小值)max
(求最大值)avg
(求平均值)group
(后果向量中的所有值均为 1)stddev
(求标准差)stdvar
(求方差)count
(计数)count_values
(对 value(样本之) 进行计个数统计)bottomk
(用于对样本值进行排序,样本值最小的 k 个元素)topk
(用于对样本值进行排序,样本值最大的 k 个元素)-
quantile
(散布统计,用于评估数据的散布统计 quantile(φ, express),其中0 ≤ φ ≤ 1
)- 比方:quantile(0.95, http_requests_total) ==> 示意找到以后样本数据中的 95% 中位数
1、表达式语法:
<aggr-op> [without|by (<label list>)] ([parameter,] <vector expression>)
或
<aggr-op>([parameter,] <vector expression>) [without|by (<label list>)]
label list:是未加引号的标签列表,比方 (code,method) 等。
without: 用于从计算结果中移除列举的标签,而保留其它标签。
by:和 without
的作用想法,示意用于从计算结果中保留列举的标签,而移除其它标签。
parameter:只能在 count_values、quantile、topk 和 bottomk 中应用。
count_values:用于工夫序列中每一个样本值呈现的次数。count_values 会为每一个惟一的样本值输入一个工夫序列,并且每一个工夫序列蕴含一个额定的标签。这个标签的名字由聚合参数指定,同时这个标签值是惟一的样本值。
quantile: 用于计算以后样本数据值的散布状况 quantile(φ, express),其中 0 ≤ φ ≤ 1。
2、示例
1、在 prometheus_http_requests_total 指标中依据 code 来分组求和
sum(prometheus_http_requests_total) by (code)
2、获取 HTTP 申请数前 5 位的时序样本数据
topk(5,prometheus_http_requests_total)
六、一些内置函数
Prometheus 提供了其它大量的内置函数,能够对时许数据进行一些解决。有些函数有默认参数,例如 year(v=vector(time()) instant-vector)
。这意味着有一个参数 v
,它是一个即时向量,如果没有提供它,它将默认为表达式 vector(time()) 的值。
1、abs 绝对值
abs(v instant-vector)
返回输出向量的所有样本的绝对值。
2、absent 判断指标名称或标签是否有值
absent(v instant-vector)
有值:** 不返回数据
没有值:** 可能返回指标名称,值返回 1
示例:
# 指标名称存在数据
absent(up)
==> no data,指标名称存在, 不返回数据
# 指标名称和标签名称值都存在数据
absent(up{job="prometheus"})
==> no data,指标名称和标签名称值都存在,不返回数据
# 指标名称和标签名称的值对应不上,即没有数据
absent(up{job="不存在的值"})
==> {job="不存在的值"} = 1,返回标签和值
# 指标名称不存在
absent(nonexistent{job="myjob"})
==> {job="myjob"} = 1
# 正则匹配的 instance 不作为返回的 labels 的一部分
absent(nonexistent{job="myjob",instance=~".*"})
==> {job="myjob"} = 1
# sum 函数返回的工夫序列不带有标签,且没有样本数据
absent(sum(nonexistent{job="myjob"}))
==> {} = 1
3、absent_over_time 和 absent 相似,只是多了一个工夫范畴
absent_over_time(nonexistent{job="myjob"}[1h])
# => {job="myjob"}
absent_over_time(nonexistent{job="myjob",instance=~".*"}[1h])
# => {job="myjob"}
absent_over_time(sum(nonexistent{job="myjob"})[1h:])
# => {}
4、ceil 四舍五入
ceil(v instant-vector)
将 v 中所有元素的样本值向上四舍五入到最靠近的整数。
node_load1 1.902324
ceil(node_load1) 2
5、changes 返回区间变量每个样本值变动的次数
changes(v range-vector)
# 如果 1 分钟内 192.168.0.1:8080 的样本值没有发生变化则返回 1
changes(node_load1{instance="192.168.0.1:8080"}[1m]) # 后果为 1
6、delta 计算区间向量第一个值和最初一个值的差值
# 返回过来两小时的 CPU 的温度差
delta(cpu_temp_celsius{host="192.168.0.1"}[2h])
留神:
该函数个别应用在 gauge
类型的工夫序列上。
7、floor 向下取整
node_load1 1.902324
floor(node_load1) 1
8、increase 返回区间向量第一个和最初一个样本的增量值
# 返回区间向量中每个工夫序列过来 5 分钟内 HTTP 申请数的增长数
increase(http_requests_total{job="prometheus"}[5m])
increase
的返回值类型只能是计数器类型,次要作用是减少图表和数据的可读性。应用 rate
函数记录规定的使用率,以便继续跟踪数据样本值的变动。
9、rate 计算区间向量 v 在工夫窗口内均匀每秒增长速率
# 计算 prometheus_http_requests_total 在 1 分钟内均匀每秒的增长速率
# 比方:1 分钟内,共增长了 1000 个申请,那么美好的增长速率为 1000/60
rate(prometheus_http_requests_total[1m])
留神:
- rate() 函数返回值类型只能用计数器,在长期趋势剖析或者告警中举荐应用这个函数。
- 当 rate()函数和聚合函数一起应用时,须要先应用 rate()函数,在应用聚合函数。比方:先应用 rate()函数,在应用 sum()函数
10、irate 计算区间向量的增长率,然而它反馈的是刹时增长率
irate 函数是通过区间向量中 最初两个样本数据
来计算区间向量的增长速率,可能体现出更好的灵敏度,通过 irate 函数绘制的图标可能更好的反馈样本数据的刹时变动状态。
# 计算 prometheus_http_requests_total 在 1 分钟内最初 2 个样本数据增长速率
irate(prometheus_http_requests_total[1m])
留神:
- irate() 函数不举荐在在长期趋势剖析或者告警中应用这个函数。
- 当 irate()函数和聚合函数一起应用时,须要先应用 rate()函数,在应用聚合函数。比方:先应用 rate()函数,在应用 sum()函数
11、predict_linear 预测工夫序列在 n 秒后的值
predict_linear(v range-vector, t scalar) 预测工夫序列 v 在 t 秒后的值。它基于简略线性回归的形式,对工夫窗口内的样本数据进行统计,从而能够对工夫序列的变化趋势做出预测。该函数的返回后果 不带有度量指标,只有标签列表。
# 预计磁盘在 4 个小时后是否被占满。predict_linear(node_filesystem_free{job="prometheus"}[2h], 4 * 3600) < 0
留神:
- 该函数个别应用在
gauge
类型的工夫序列上。
12、sort 对向量按元素的值进行升序排序
# 样本值升序排序
sort(prometheus_http_requests_total)
13、sort_desc 对向量按元素的值进行降序排序
# 样本值倒序排序
sort_desc(prometheus_http_requests_total)
七、参考文章
1、https://github.com/google/re2/wiki/Syntax
2、https://prometheus.io/docs/prometheus/latest/querying/basics/