Prometheus下的 PQL
【0】介绍
Prometheus提供了一种称为PromQL(Prometheus查询语言)的功能查询语言,它使用户可以实时选择和汇总时间序列数据。
表达式的结果可以显示为图形,可以在Prometheus的表达式浏览器中显示为表格数据,也可以由外部系统通过HTTP API使用。
【1】表达式的类型
【1.1】4大基本类型
- Instant vector(向量) -一组时间序列,每个时间序列包含一个样本,所有样本共享相同的时间戳(简单理解:具体的采集指标的值)
- Range vector(向量)-一组时间序列,其中包含每个时间序列随时间变化的一系列数据点(简单理解:查看某个时间范围的数据)
- Scalar(标量) - 一个简单的数字浮点值(简答理解:数字)
- String -一个简单的字符串值;目前未使用
具体化为:
Prometheus 四种指标类型
1、Counter (计算器)
counter类型代表一种样本数据单调递增的指标,即只增不减,除非监控系统发生了重置。
2、Gauge(仪表盘)
Gauge类型代表一种样本数据可以任意变化的指标,即可增可减。
3、Histogram(直方图)
Histogram在一段时间范围内对数据进行采样(通常是青丘狐传说持续时间或响应大小等),并将其计入可配置的存储桶中,后续可通过制定区间筛选样本,也可以统计样本总数,最后一般将数据展示为直方图,
- 样本的值分布在 bucket 中的数量,命名为
<basename>_bucket{le="<上边界>"}
。解释的更通俗易懂一点,这个值表示指标值小于等于上边界的所有样本数量
- 所有样本值的大小总和,命名为
<basename>_sum
。 - 样本总数,命名为
<basename>_count
。值和<basename>_bucket{le="+Inf"}
相同。
4、Summary(摘要)
与Histogram类似类型,用于表示一段时间内的数据采样结果(通常是请求持续时间或响应大小等),但它直接存储了分位数(通过客户端计算,然后展示出来),而不是通过区间计算
- 样本值的分位数分布情况,命名为
<basename>{quantile="<φ>"}
。 - 所有样本值的大小总和,命名为
<basename>_sum
。 - 所有样本值的大小总和,命名为
<basename>_sum
。
【1.2】Instant vector (即时向量选择器)
本示例选择所有具有 prometheus_http_requests_total 度量标准名称的时间序列:
prometheus_http_requests_total
包含这么多呢
过在花括号({}
)后面加上逗号分隔的标签匹配器列表,可以进一步过滤这些时间序列。
prometheus_http_requests_total{code="302",handler="/",instance="localhost:9090",job="prometheus"}
也可以:node_load1{job='agent_linux'} 是吧
【1.3】等于/不等于匹配符
=
:选择与提供的字符串完全相同的标签。!=
:选择不等于提供的字符串的标签。=~
:选择与提供的字符串进行正则表达式匹配的标签。!~
:选择与提供的字符串不进行正则表达式匹配的标签。
例如,此选择所有http_requests_total
的时间序列staging
, testing
以及development
环境和HTTP比其他方法GET
。
http_requests_total{environment=~"staging|testing|development",method!="GET"}
向量选择器必须指定一个名称或至少一个与空字符串不匹配的标签匹配器。以下表达式是非法的:
{job=~".*"} # Bad!
相反,这些表达式都是有效的,因为它们都具有与空标签值不匹配的选择器。
{job=~".+"} # Good!
{job=~".*",method="get"} # Good!
【1.4】range vector(范围向量选择器)
范围向量文字的工作方式与即时向量文字相同,不同之处在于它们从当前即时中选择了一系列样本。从句法上讲,范围持续时间附加在[]
向量选择器末尾的方括号()中,以指定应为每个结果范围向量元素提取多远的时间值。
持续时间指定为数字,紧随其后的是以下单位之一:
s
-秒m
- 分钟h
- 小时d
- 天w
-周y
-年
在此示例中,我们选择所有时间序列在过去5分钟内记录的所有值,这些时间序列的度量标准名称http_requests_total
和job
标签设置为prometheus
:
http_requests_total{job="prometheus"}[5m]
【1.5】Offset modifier(偏移量修改器)
所述offset
改性剂可以改变时间为查询中的个别时刻和范围矢量偏移。
例如,以下表达式返回http_requests_total
相对于当前查询评估时间的过去5分钟的值 :
http_requests_total offset 5m
请注意,offset
修饰符始终需要立即跟随选择器,即以下内容将是正确的:
sum(http_requests_total{method="GET"} offset 5m) // GOOD.
虽然以下是不正确的:
sum(http_requests_total{method="GET"}) offset 5m // INVALID.
范围向量的工作原理相同。这将返回http_requests_total
一周前的5分钟费率 :
rate(http_requests_total[5m] offset 1w)
【1.6】子查询
子查询允许您针对给定的范围和分辨率运行即时查询。子查询的结果是范围向量。
句法: <instant_query> '[' <range> ':' [<resolution>] ']' [ offset <duration> ]
<resolution>
是可选的。默认值为全局评估间隔
PromQL支持以开头的行注释 # this is a comment
【2】二元运算
【2.1】二元算数运算
Prometheus中存在以下二进制算术运算符:
+
(加成)-
(减法)*
(乘法)/
(师)%
(取模)^
(幂/幂)
(1)标量和向量
【标量】:就是数字 【向量】:就是采集指标得到的值
官网描述:
(我的理解:就是两个数字做操作,得到的也是一个数字)在两个标量之间,其行为显而易见:它们求值另一个标量,这是将运算符应用于两个标量操作数的结果。
(我的理解:就是采集指标下值可能有很多个,如果做 * 2操作,那么所有值都要 * 2)在瞬时向量和标量之间,将运算符应用于向量中每个数据样本的值。例如,如果时间序列瞬时向量乘以2,则结果是另一个向量,其中原始向量的每个样本值都乘以2。
(我的理解:就是两个采集指标下面均可能有多个值,如果相乘,那么就向左边的指标一一匹配相乘,没匹配到的就不显示)在两个即时向量之间,将二进制算术运算符应用于左侧向量中的每个条目,并将其 应用于右侧向量中的匹配元素。结果将传播到结果向量中,并且分组标签成为输出标签集。指标名称已删除。在右侧向量中找不到匹配条目的条目不属于结果。
【2.2】二元比较运算
在Prometheus系统中,比较二元操作符有:
==
等于!=
不等于>
大于<
小于>=
大于等于<=
小于等于
两个数字之间:变成 bool 来做比较,结果返回 0 或者 1,即真 或者 假
数字和指标之间:把这个比较应用于指标中的每个值。
【2.3】二元逻辑运算
逻辑/集合二元操作符只能作用在即时向量, 包括:
and
交集or
并集unless
补集
并交补就不用说了吧。
vector1 and vector2
得到一个由vector1
元素组成的向量,其中vector2
中的元素具有完全匹配的标签集。 其他元素被删除。 度量标准名称和值从左侧向量转移
vector1 or vector2
得到包含vector1
的所有原始元素(标签集+值)的向量以及vector2
中vector1
中没有匹配标签集的所有元素。。
vector1 unless vector2
得到一个由vector1
元素组成的向量,其中vector2
中没有元素,具有完全匹配的标签集。 两个向量中的所有匹配元素
【2.4】聚合操作符
Prometheus支持以下内置聚合运算符,这些运算符可用于聚合单个即时向量的元素,从而生成具有聚合值的较少元素的新向量:
sum
(在维度上求和)max
(在维度上求最大值)min
(在维度上求最小值)avg
(在维度上求平均值)stddev
(求标准差)stdvar
(求方差)count
(统计向量元素的个数)count_values
(统计相同数据值的元素数量)bottomk
(样本值第k个最小值)topk
(样本值第k个最大值)quantile
(统计分位数)
这些运算符可以用于聚合所有标签维度,也可以通过包含without
或by
子句来保留不同的维度。
<aggr-op>([parameter,] <vector expr>) [without | by (<label list>)] [keep_common]
parameter
仅用于count_values
,quantile
,topk
和bottomk
。不从结果向量中删除列出的标签,而所有其他标签都保留输出。 by
相反并删除未在by
子句中列出的标签,即使它们的标签值在向量的所有元素之间是相同的。
count_values
输出每个唯一样本值的一个时间序列。每个系列都有一个额外的标签。该标签的名称由聚合参数给出,标签值是唯一的样本值。每个时间序列的值是样本值存在的次数。
topk
和bottomk
与其他聚合器的不同之处在于,输入样本的子集(包括原始标签)在结果向量中返回。 by
和without
仅用于存储输入向量。
例:
如果度量标准http_requests_total
具有按应用程序,实例和组标签扇出的时间序列,我们可以通过以下方式计算每个应用程序和组在所有实例上看到的HTTP请求总数:
sum(http_requests_total) without (instance)
等价于:
sum(http_requests_total)
要计算运行每个构建版本的二进制文件的数量,我们可以编写:
count_values("version", build_version)
要在所有实例中获取5个最大的HTTP请求计数,我们可以编写:
topk(5, http_requests_total)
(案例)聚合案例
1、忽略某个标签,如下忽略cpu标签 avg without(cpu) (rate(node_cpu[2m]))
【2.5】二元运算符的优先级
以下列表显示了Prometheus中二进制运算符的优先级,从最高到最低。
- ^
- *, /, %
- +, -
- ==, !=, <=, <, >=, >
- and, unless
- or
具有相同优先级的运算符是左关联的。 例如,2 * 3%2
相当于(2 * 3)%2
。但是^
是右关联的,因此2 ^ 3 ^ 2
相当于2 ^(3 ^ 2)
。
【3】常用函数
rate(node_network_receive_bytes_total[1m])
计算1分钟内的平均值
increase(node_network_receive_bytes_total{device="eth0"}[1m])
计算1分钟内的 第一个值和最后一个值 的差值
irate(http_requests_total{job="api-server"}[5m])
计算5分钟内,最后的两个值的差值
一些函数有默认的参数,例如:year(v=vector(time()) instant-vector)
。v是参数值,instant-vector是参数类型。vector(time())是默认值。
abs()
abs(v instant-vector)
返回输入向量的所有样本的绝对值。
absent()
absent(v instant-vector)
,如果赋值给它的向量具有样本数据,则返回空向量;如果传递的瞬时向量参数没有样本数据,则返回不带度量指标名称且带有标签的样本值为1的结果
当监控度量指标时,如果获取到的样本数据是空的, 使用absent方法对告警是非常有用的
absent(nonexistent{job="myjob"}) # => key: value = {job="myjob"}: 1
absent(nonexistent{job="myjob", instance=~".*"}) # => {job="myjob"} 1 so smart !
absent(sum(nonexistent{job="myjob"})) # => key:value {}: 0
ceil()
ceil(v instant-vector)
是一个向上舍入为最接近的整数。
changes()
changes(v range-vector)
输入一个范围向量, 返回这个范围向量内每个样本数据值变化的次数。
clamp_max()
clamp_max(v instant-vector, max scalar)
函数,输入一个瞬时向量和最大值,样本数据值若大于max,则改为max,否则不变
clamp_min()
clamp_min(v instant-vector)
函数,输入一个瞬时向量和最大值,样本数据值小于min,则改为min。否则不变
count_saclar()
count_scalar(v instant-vector)
函数, 输入一个瞬时向量,返回key:value="scalar": 样本个数。而count()
函数,输入一个瞬时向量,返回key:value=向量:样本个数,其中结果中的向量允许通过by
条件分组。
day_of_month()
day_of_month(v=vector(time()) instant-vector)
函数,返回被给定UTC时间所在月的第几天。返回值范围:1~31。
day_of_week()
day_of_week(v=vector(time()) instant-vector)
函数,返回被给定UTC时间所在周的第几天。返回值范围:0~6. 0表示星期天。
days_in_month()
days_in_month(v=vector(time()) instant-vector)
函数,返回当月一共有多少天。返回值范围:28~31.
delta()
delta(v range-vector)
函数,计算一个范围向量v的第一个元素和最后一个元素之间的差值。返回值:key:value=度量指标:差值
下面这个表达式例子,返回过去两小时的CPU温度差:
delta(cpu_temp_celsius{host="zeus"}[2h])
delta
函数返回值类型只能是gauges。
deriv()
deriv(v range-vector)
函数,计算一个范围向量v中各个时间序列二阶导数,使用简单线性回归
deriv
二阶导数返回值类型只能是gauges。
drop_common_labels()
drop_common_labels(instant-vector)
函数,输入一个瞬时向量,返回值是key:value=度量指标:样本值,其中度量指标是去掉了具有相同标签。 例如:http_requests_total{code="200", host="127.0.0.1:9090", method="get"} : 4, http_requests_total{code="200", host="127.0.0.1:9090", method="post"} : 5, 返回值: http_requests_total{method="get"} : 4, http_requests_total{code="200", method="post"} : 5
exp()
exp(v instant-vector)
函数,输入一个瞬时向量, 返回各个样本值的e指数值,即为e^N次方。特殊情况如下所示:
Exp(+inf) = +Inf Exp(NaN) = NaN
floor()
floor(v instant-vector)
函数,与ceil()
函数相反。 4.3 为 4 。
histogram_quantile()
histogram_quatile(φ float, b instant-vector)
函数计算b向量的φ-直方图 (0 ≤ φ ≤ 1) 。参考中文文献[https://www.howtoing.com/how-to-query-prometheus-on-ubuntu-14-04-part-2/]
holt_winters()
holt_winters(v range-vector, sf scalar, tf scalar)
函数基于范围向量v,生成事件序列数据平滑值。平滑因子sf
越低, 对老数据越重要。趋势因子tf
越高,越多的数据趋势应该被重视。0< sf, tf <=1。 holt_winters
仅用于gauges
hour()
hour(v=vector(time()) instant-vector)
函数返回被给定UTC时间的当前第几个小时,时间范围:0~23。
idelta()
idelta(v range-vector)
函数,输入一个范围向量,返回key: value = 度量指标: 每最后两个样本值差值。
increase()
increase(v range-vector)
函数, 输入一个范围向量,返回:key:value = 度量指标:last值-first值,自动调整单调性,如:服务实例重启,则计数器重置。与delta()
不同之处在于delta是求差值,而increase返回最后一个减第一个值,可为正为负。
下面的表达式例子,返回过去5分钟,连续两个时间序列数据样本值的http请求增加值。
increase(http_requests_total{job="api-server"}[5m])
increase
的返回值类型只能是counters,主要作用是增加图表和数据的可读性,使用rate
记录规则的使用率,以便持续跟踪数据样本值的变化。
irate
irate(v range-vector)
函数, 输入:范围向量,输出:key: value = 度量指标: (last值-last前一个值)/时间戳差值。它是基于最后两个数据点,自动调整单调性, 如:服务实例重启,则计数器重置。
下面表达式针对范围向量中的每个时间序列数据,返回两个最新数据点过去5分钟的HTTP请求速率。
irate(http_requests_total{job="api-server"}[5m])
irate
只能用于绘制快速移动的计数器。因为速率的简单更改可以重置FOR子句,利用警报和缓慢移动的计数器,完全由罕见的尖峰组成的图形很难阅读。
label_replace()
对于v中的每个时间序列,label_replace(v instant-vector, dst_label string, replacement string, src_label string, regex string)
将正则表达式与标签值src_label匹配。如果匹配,则返回时间序列,标签值dst_label被替换的扩展替换。$1替换为第一个匹配子组,$2替换为第二个等。如果正则表达式不匹配,则时间序列不会更改。
另一种更容易的理解是:label_replace
函数,输入:瞬时向量,输出:key: value = 度量指标: 值(要替换的内容:首先,针对src_label标签,对该标签值进行regex正则表达式匹配。如果不能匹配的度量指标,则不发生任何改变;否则,如果匹配,则把dst_label标签的标签纸替换为replacement 下面这个例子返回一个向量值a带有foo
标签:label_replace(up{job="api-server", serice="a:c"}, "foo", "$1", "service", "(.*):.*")
ln()
ln(v instance-vector)
计算瞬时向量v中所有样本数据的自然对数。特殊例子:
ln(+Inf) = +Inf ln(0) = -Inf ln(x<0) = NaN ln(NaN) = NaN
log2()
log2(v instant-vector)
函数计算瞬时向量v中所有样本数据的二进制对数。
log10()
log10(v instant-vector)
函数计算瞬时向量v中所有样本数据的10进制对数。相当于ln()
minute()
minute(v=vector(time()) instant-vector)
函数返回给定UTC时间当前小时的第多少分钟。结果范围:0~59。
month()
month(v=vector(time()) instant-vector)
函数返回给定UTC时间当前属于第几个月,结果范围:0~12。
predict_linear()
predict_linear(v range-vector, t scalar)
预测函数,输入:范围向量和从现在起t秒后,输出:不带有度量指标,只有标签列表的结果值。
例如:predict_linear(http_requests_total{code="200",instance="120.77.65.193:9090",job="prometheus",method="get"}[5m], 5)
结果:
{code="200",handler="query_range",instance="120.77.65.193:9090",job="prometheus",method="get"} 1
{code="200",handler="prometheus",instance="120.77.65.193:9090",job="prometheus",method="get"} 4283.449995397104
{code="200",handler="static",instance="120.77.65.193:9090",job="prometheus",method="get"} 22.99999999999999
{code="200",handler="query",instance="120.77.65.193:9090",job="prometheus",method="get"} 130.90381188596754
{code="200",handler="graph",instance="120.77.65.193:9090",job="prometheus",method="get"} 2
{code="200",handler="label_values",instance="120.77.65.193:9090",job="prometheus",method="get"} 2
rate()
rate(v range-vector)
函数, 输入:范围向量,输出:key: value = 不带有度量指标,且只有标签列表:(last值-first值)/时间差s
rate(http_requests_total[5m])
结果:
{code="200",handler="label_values",instance="120.77.65.193:9090",job="prometheus",method="get"} 0
{code="200",handler="query_range",instance="120.77.65.193:9090",job="prometheus",method="get"} 0
{code="200",handler="prometheus",instance="120.77.65.193:9090",job="prometheus",method="get"} 0.2
{code="200",handler="query",instance="120.77.65.193:9090",job="prometheus",method="get"} 0.003389830508474576
{code="422",handler="query",instance="120.77.65.193:9090",job="prometheus",method="get"} 0
{code="200",handler="static",instance="120.77.65.193:9090",job="prometheus",method="get"} 0
{code="200",handler="graph",instance="120.77.65.193:9090",job="prometheus",method="get"} 0
{code="400",handler="query",instance="120.77.65.193:9090",job="prometheus",method="get"} 0
rate()
函数返回值类型只能用counters, 当用图表显示增长缓慢的样本数据时,这个函数是非常合适的。
注意:当rate函数和聚合方式联合使用时,一般先使用rate函数,再使用聚合操作, 否则,当服务实例重启后,rate无法检测到counter重置。
resets()
resets()
函数, 输入:一个范围向量,输出:key-value=没有度量指标,且有标签列表[在这个范围向量中每个度量指标被重置的次数]。在两个连续样本数据值下降,也可以理解为counter被重置。 示例:
resets(http_requests_total[5m])
结果:
{code="200",handler="label_values",instance="120.77.65.193:9090",job="prometheus",method="get"} 0
{code="200",handler="query_range",instance="120.77.65.193:9090",job="prometheus",method="get"} 0
{code="200",handler="prometheus",instance="120.77.65.193:9090",job="prometheus",method="get"} 0
{code="200",handler="query",instance="120.77.65.193:9090",job="prometheus",method="get"} 0
{code="422",handler="query",instance="120.77.65.193:9090",job="prometheus",method="get"} 0
{code="200",handler="static",instance="120.77.65.193:9090",job="prometheus",method="get"} 0
{code="200",handler="graph",instance="120.77.65.193:9090",job="prometheus",method="get"} 0
{code="400",handler="query",instance="120.77.65.193:9090",job="prometheus",method="get"} 0
resets只能和counters一起使用。
round()
round(v instant-vector, to_nearest 1= scalar)
函数,与ceil
和floor
函数类似,输入:瞬时向量,输出:指定整数级的四舍五入值, 如果不指定,则是1以内的四舍五入。
scalar()
scalar(v instant-vector)
函数, 输入:瞬时向量,输出:key: value = "scalar", 样本值[如果度量指标样本数量大于1或者等于0, 则样本值为NaN, 否则,样本值本身]
sort()
sort(v instant-vector)
函数,输入:瞬时向量,输出:key: value = 度量指标:样本值[升序排列]
sort_desc()
sort(v instant-vector
函数,输入:瞬时向量,输出:key: value = 度量指标:样本值[降序排列]
sqrt()
sqrt(v instant-vector)
函数,输入:瞬时向量,输出:key: value = 度量指标: 样本值的平方根
time()
time()
函数,返回从1970-01-01到现在的秒数,注意:它不是直接返回当前时间,而是时间戳
vector()
vector(s scalar)
函数,返回:key: value= {}, 传入参数值
year()
year(v=vector(time()) instant-vector)
, 返回年份。
_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): 范围向量内每个度量指标的总体标准方差。
摘取来自Github 权侵删!摘取来自Github 权侵删!摘取来自Github 权侵删!摘取来自Github 权侵删!摘取来自Github 权侵删!摘取来自Github 权侵删!
相关参考:http://flashcat.cloud/docs/content/flashcat-partner/prometheus/promql/operators/