Prometheus-PQL
以容器内存使用量container_memory_usage_bytes等时序为例,演示PQL的语法
1、向量表达式<vector expr>
- <instant-vector> 向量,一个或多个时序
- <Scalar> 标量
- <range-vector> 一定时间范围内的向量
1.1 查询当前值
容器很多,每个容器都有container_memory_usage_bytes这个时序,所以会查询出很多值
以下是一条完整的时间序列:
container_memory_usage_bytes{container="POD",container_name="POD",endpoint="https-metrics",id="/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod0c5e318f_85d4_11e9_bd89_005056966598.slice/docker-8a2b6d97ce1c2829fdccbeb1e71f9183da4de1cdf1a865852c485e12eaed4147.scope",image="k8s.gcr.io/pause:3.1",instance="22.22.3.241:10250",job="kubelet",name="k8s_POD_kube-proxy-r5q5h_kube-system_0c5e318f-85d4-11e9-bd89-005056966598_0",namespace="kube-system",node="prometheus01",pod="kube-proxy-r5q5h",pod_name="kube-proxy-r5q5h",service="kubelet"}
1.2 基于标签值进行过滤
时序通常包含很多标签,可以使用字符串、正则表达式来过滤标签值。支持的运算: =: 等于、!=: 不等于、=~: 匹配正则表达式、!~: 不匹配正则表达式
container_memory_usage_bytes{namespace="kube-system",node=~"node01|node02",name!~"^k8s.*"}
#过滤namespace="kube-system",node="node01"或者"node02",name不以K8s开头
1.3 查询一定时间范围的值
在上一个查询的基础上,增加2分钟的时间范围,获取2分钟内的多个值
container_memory_usage_bytes{namespace="kube-system",node=~"node01|node02",name!~"^k8s.*"}[2m]
#获取2分钟内的多个值
时间范围的单位可以是:s秒s分h 小时d 天w周y年;
时间范围2分钟,可以看到3到4个值,说明target是每30s获取一次,查询结果中可以看到时间戳;
container_memory_usage_bytes{namespace="kube-system",node=~"node01|node02",name!~"^k8s.*"} offset 1m
#获取1分钟前的单个值
获取3分钟前到1分钟前的多个值,时间范围2m,必须在offset之前
container_memory_usage_bytes{namespace="kube-system",node=~"node01|node02",name!~"^k8s.*"}[2m] offset 1m
#获取3分钟前到1分钟前的多个值
2、算术运算
2.1数值计算
可以通过数学运算,改变查询出来的值:
支持的运算符:+ 、- 、*、/ 、% (取模)、^ (幂)
container_memory_usage_bytes{namespace="kube-system",node=~"node01|node02",name!~"^k8s.*"} offset 1m /1024/1024
#通过运算,将字节单位的数值计算成以M为单位
2.2 比较和过滤
通过比较运算,过滤出符合条件的值
支持的比较运算符:== (等于)、!= (不等于)、> (大于)、< (小于)、>= (大于等于) <= (小于等于)
container_memory_usage_bytes{namespace="kube-system",node=~"node01|node02",name!~"^k8s.*"} offset 1m /1024/1024>32
#过滤出内存使用大于32M的容器
还可以在比较运算符后加上bool,返回比较结果,1表示True,0表示false,不过滤
container_memory_usage_bytes{namespace="kube-system",node=~"node01|node02",name!~"^k8s.*"} offset 1m /1024/1024> bool 32
#返回bool型
比较时,前面的值是标量,必须使用bool,返回1或者0
container_memory_usage_bytes{namespace="kube-system",node=~"node01|node02",name!~"^k8s.*"} offset 1m + 1024*50< container_memory_usage_bytes{namespace="kube-system",node=~"node01|node02",name!~"^k8s.*"}
#查询最近1分钟,内存增加50k的容器
2.3 逻辑运算
支持 and、or、unless运算,不支持值的运算
- A or B
将A和B两个结果合并
container_memory_usage_bytes{pod="kubernetes-dashboard-5f7b999d65-rd5rn"}
#可以查询到3个向量
kube_pod_labels{pod="kubernetes-dashboard-5f7b999d65-rd5rn"}
#可以查询到1个向量
container_memory_usage_bytes{pod="kubernetes-dashboard-5f7b999d65-rd5rn"} or kube_pod_labels{pod="kubernetes-dashboard-5f7b999d65-rd5rn"}
#使用or将两个结果合并,得到4个向量
- A and B
A和B的标签必须完全一致,查询结果保留A的名称、值和标签,不完全一致的丢弃
container_memory_usage_bytes{pod="busybox-56546db479-hdf65"}
#可以查询到3个向量
container_memory_max_usage_bytes{id="/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod22f01897_042a_11ea_91cd_005056967167.slice/docker-74b609f325ecf8262983d21f02446d58c75bfb4dca73c5f7317c3954c5fc4954.scope"}
#可以查询到1个向量
container_memory_usage_bytes{id="/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod22f01897_042a_11ea_91cd_005056967167.slice/docker-74b609f325ecf8262983d21f02446d58c75bfb4dca73c5f7317c3954c5fc4954.scope"} and container_memory_max_usage_bytes{pod="busybox-56546db479-hdf65"}
#and操作后,只有一个完全匹配的向量
A unless B:
删除A中与B标签完全匹配的时序,保留不匹配的
container_memory_max_usage_bytes{pod="busybox-56546db479-hdf65"} unless container_memory_usage_bytes{id="/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod22f01897_042a_11ea_91cd_005056967167.slice/docker-74b609f325ecf8262983d21f02446d58c75bfb4dca73c5f7317c3954c5fc4954.scope"}
3 匹配运算
3.1 一对一
<vector expr> <bin-op> ignoring(<label list>) <vector expr>
<vector expr> <bin-op> on(<label list>) <vector expr>
<vector expr>向量表达式
<bin-op>算术运算
Ignoring 忽略标签、on选定标签
默认需要匹配所有标签,可以选择忽略,或者只选择某些标签
原始数据如下:
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
获取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
method_code:http_errors:rate5m{code="500"} / ignoring(code) method:http_requests:rate5m
除以method:http_requests:rate5m中标签method标签相同
(method_code:http_errors:rate5m包含method和code两个标签,由于忽略了code,所以只匹配method)的向量,查询结果如下:
{method="get"} 0.04 // 24 / 600
{method="post"} 0.05 // 6 / 120
3.2 一对多和多对一
<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>
增加了group_left、group_right操作:
method_code:http_errors:rate5m / ignoring(code) group_left method:http_requests:rate5m
忽略code标签,匹配method标签,group_left表示多对一,group_right表示一对多,在结果中保留多一侧的所有标签
{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
4、聚合运算
支持的运算有:
- sum (求和)
- min (最小值)
- max (最大值)
- avg (平均值)
- stddev (标准差)
- stdvar (方差)
- count (计算元素数量)
- count_values (计算相同元素数量)
- bottomk (元素最小值)
- topk (元素最大值)
- quantile (百分比最大值)
可以配合by或者without进行标签过滤
- Min、max、avg、sum、count
sum (container_memory_usage_bytes) by(node,namespace)
#根据标签node和namespace分组求和,只有一个标签也会单独分组
- Stddev标准差/stdvar方差
container_memory_usage_bytes{node="ingressnode01",pod="node-exporter-kf2cr"}/1024/1024
#获取当前值
0.04296875
24.53125
24.91015625
49.55859375
stddev(container_memory_usage_bytes{node="ingressnode01",pod="node-exporter-kf2cr"}/1024/1024 )
#Stddev计算得到标准差17.506975445872715
- count_value 统计value相同的元素个数
count_values ("newlabel",kube_deployment_created)
#统计value相同的元素个数,形成标签为"newlabel"=value的新的向量
- bottomk/topk 获取最小和最大的n个值
bottomk (2,container_memory_usage_bytes{node="ingressnode01",pod="node-exporter-kf2cr"}/1024/1024)
#获取最小的2个值
- quantile 获取summary的历史最大值
go_gc_duration_seconds{quantile="0.25",pod="prometheus-operator-74d449f6b4-q6bjn"}
#获取summary go_gc_duration_seconds中quantile="0.25"的数据
quantile(0.25,go_gc_duration_seconds{pod="prometheus-operator-74d449f6b4-q6bjn"})
#获取summary go_gc_duration_seconds中quantile="0.25"的历史最大值
5、运算优先
- 1、^
- 2、*, /, %
- 3、+, -
- 4、==, !=, <=, <, >=, >
- 5、and, unless
- 6、Or
6、函数
- abs(v instant-vector) 绝对值
- absent(v instant-vector) v存在返回空,v不存在返回1
- ceil(v instant-vector) 向上取整,当前值为整数则不变
- floor(v instant-vector) 向下取整,当前值为整数则不变
- sqrt(v instant-vector) 返回v中所有向量的平方根
- exp(v instant-vector) 计算v中所有元素自然常数e为底的指数函数
apiserver_request_count{verb="LIST",resource="bgppeers"}
# 获取向量值
exp(apiserver_request_count{verb="LIST",resource="bgppeers"})
# 获得值9,20,2,2,获取常数e为底的指数
- resets(v range-vector) 对于每个 time series , 它都返回一个 counter resets的次数
- changes(v ) 时间范围内更改的次数
changes(container_memory_usage_bytes{pod_name="node-exporter-62mkc"}[5m])
# 5m之内时序值变化的次数
- round(v, t) 按四舍五入取接近当前值的t的整数倍的值,t可以是小数和分数
round(container_memory_usage_bytes{pod="kubernetes-dashboard-5f7b999d65-rd5rn"}/1024/1024 ,1/33)
- clamp_max(v, max scalar) 限制v中所有元素的样本值,使其上限为max
- clamp_min(v, min scalar) 限制v中所有元素的样本值,使其下限为min
container_memory_usage_bytes{pod_name="node-exporter-62mkc"}
#获取当前值
clamp_max(container_memory_usage_bytes{pod_name="node-exporter-62mkc"},81920)
#将超过上限的值改为81920
- time()
返回从1970-1-1起至今的秒数,UTC时间 - Vector() 将标量转化为没有标签的向量
- year(v=vector(time()) instant-vector) 返回UTC中给定时间的年份
- day_of_month(v=vector(time()) instant-vector) 返回UTC中给定时间的月中的某一天,返回值为1到31
- day_of_week(v=vector(time()) instant-vector) 返回UTC中给定时间的当周中的某一天,返回值为0到6
- days_in_month(v=vector(time()) instant-vector) 返回UTC中给定时间的一个月的天数,返回值28到31
- hour(v=vector(time()) instant-vector) 返回UTC中给定时间的当天中的某一小时,返回值为0到23
- minute(v=vector(time()) instant-vector) 返回UTC中给定时间的小时中的某分钟,返回值为0到59
minute(vector(time()-120))
#当前时间为44,获取2分钟前的分值
- delta(v range-vector) 计算第一个值和最后一个值的差值
- idelta(v range-vector) 计算最新的2个样本值之间的差别
delta(container_memory_usage_bytes{id="/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod0c5e318f_85d4_11e9_bd89_005056966598.slice/docker-8a2b6d97ce1c2829fdccbeb1e71f9183da4de1cdf1a865852c485e12eaed4147.scope"}[1h])
#计算过去1个小时的第一个值和最后一个值的差值
- deriv(v range-vector) 计算每个time series的每秒的导数(derivative)
deriv(container_memory_usage_bytes{id="/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod0c5fb204_85d4_11e9_bd89_005056966598.slice/docker-b4caa53df37466f3ef3df22b325df7d45fa1a0dd5e2403e836af617efd1c5e5d.scope"}[5m])
-
histogram_quantile(φ float, b instant-vector) 从buckets类型的向量中计算φ(0 ≤ φ ≤ 1)百分比的样本的最大值
-
holt_winters(v range-vector, sf scalar, tf scalar) 根据范围向量中的范围产生一个平滑的值
-
increase(v range-vector) 计算指定范围内的增长值, 它会在单调性发生变化时(如由于目标重启引起的计数器复位)自动中断
http_request_total{statuscode="200",instance="10.244.17.198:3000",handler="/datasources/proxy/:id/*"}[5m]
#5分钟之内的值
increase(http_request_total{statuscode="200",instance="10.244.17.198:3000",handler="/datasources/proxy/:id/*"}[5m])
#获取5分钟之内的增长
- irate(v range-vector)
计算每秒的平均增长值, 基于的是最新的2个数据点
irate(prometheus_http_request_duration_seconds_count{endpoint="web",handler="/api/v1/query",instance="10.244.140.87:9090",job="prometheus-k8s",namespace="monitoring",pod="prometheus-k8s-1",service="prometheus-k8s"}[1h])
#最近的两个值是3623189 @1573800803.264和3623205 @1573800833.264,数值相差16,时间相差30,16/30=0.5333333333
- rate(v range-vector)
计算每秒的平均增长值
rate(prometheus_http_request_duration_seconds_count{endpoint="web",handler="/api/v1/query",instance="10.244.140.87:9090",job="prometheus-k8s",namespace="monitoring",pod="prometheus-k8s-1",service="prometheus-k8s"}[1h])
- sort(v instant-vector) 对向量按元素的值进行升序排序
- sort_desc(v instant-vector) 对向量按元素的值进行降序排序
sort_desc(container_memory_usage_bytes)
#对向量按元素的值进行降序排序