一、介绍
就如同SQL中有一些内置函数,PromQL中也存在一些函数,我们可以在进行PromQL表达式进行使用,完成一些数据的处理。
学习函数前至少需要知道如下概念,因为函数的概念和传入的数据类型有关
- 瞬时数据 (Instant vector): 包含一组时序,每个时序只有一个点,例如:
http_requests_total
- 区间数据 (Range vector): 包含一组时序,每个时序有多个点,例如:
http_requests_total[5m]
- 纯量数据 (Scalar): 纯量只有一个数字,没有时序,例如:
count(http_requests_total)
二、irate与rate
irate和rate都会用于计算某个指标在一定时间间隔内的变化速率。
但是它们的计算方法有所不同:
- irate取的是在指定时间范围内的最近两个数据点来算速率;
- irate适合快速变化的计数器(counter)
- rate取的是在指定时间范围内的所有数据点,算出一组速率,然后取平均值作为结果。
- rate适合缓慢变化的计数器(counter)
如下计算QPS:
- sum(irate(http_server_requests_seconds_count{application="hubble-api-open"}[5m])):用irate计算QPS
- 计算方式:(v[-1] - v[0]) / (time(v[-1]) - time(v[0]))
- 使用rate计算快速变化的样本平均增长率时,容易陷入长尾问题,因为它用平均值将峰值削平了,无法反映时间窗口内样本数据的快速变化。与rate类似,irate同样可以计算counter的平均增长率,但其反映出的是瞬时增长率。
- sum(rate(http_server_requests_seconds_count{application="hubble-api-open"}[5m])) :用rate计算QPS
- 计算方式:(lastValue - firstValue) / Range
- 经过计算后,就可以得到QPS,即每秒的请求数
经过如下两个图表的对比,明显发现,irate计算出的图表比较尖锐,rate计算出的比较平滑
三、聚合函数:sum
sum (求和)
上面第二点计算QPS的时候,其实已经用到了sum函数:sum(irate(http_server_requests_seconds_count{application="hubble-api-open"}[5m]))
先看不使用sum的情况:irate(http_server_requests_seconds_count{application="hubble-api-open"}[5m])
如下图所示:查出的是每个uri的qps,我们需要计算的是应用总的QPS,因此要用sum,即把所有QPS加起来
根据某个标签求和:
sum by (user)(cortex_distributor_received_samples_total)
按照用户算qps
等价于
sum(cortex_distributor_received_samples_total) by (user)
四、 absent
absent(v instant-vector) :传入一个瞬时非空向量则返回空向量,否则返回不带名称值为1的指标,用来监控空数据的情况,即nodata监控
五、delta与idelta
delta(v range-vector) :参数是一个区间向量,返回一个瞬时向量。它计算一个区间向量 v 的第一个元素和最后一个元素之间的差值
- 和张羽看了prometheus的实现代码,可以简单理解为就是最后一个点的值减去第一个点的值。
- 但是实际上真实场景中,第一个点和最后一个点不可能每次都正好每和时间区间的第一个时间点和最后一个时间点相吻合,所以prometheus在代码中做了大量的计算,由于涉及到很多除法运算,因此结果一般都是小数
idelta(v range-vector) :参数是一个区间向量, 返回一个瞬时向量。它计算最新的 2 个样本值之间的差值。(当区间内仅有一个向量时无返回值)
六、聚合函数:avg
avg (平均值)。
七、聚合函数:max、min
min (最小值)、max (最大值)
八、聚合函数:count
count (样本数量计数)
案例:count,计算大于12189696的样本数量,如下,结果有4个
九、bottomk与topk
bottomk (样本值最小的 k 个元素)、topk (样本值最大的k个元素,和bottomk正好相反,用法一致)
案例:bottomk(2,key),如下,查出最小的两个值
案例:topk(3,key)
如下案例是从grafana配置的查询中获取的一段,@ end()表示grafana查询时间范围的结束时间,@ start()表示查询时间范围的开始时间。
我们通过从当前查询范围的结束时间的速率中减去起始时间的速率,得到每个用户在指定时间范围内接收到的样本总数的差值。这样,我们就可以得到一个按用户分组的差值列表,用于后续分析和展示。
注意:
PromQL(Prometheus查询语言)中的 "@" 符号用于指定查询结果的具体时间。当需要在PromQL查询中锁定到特定的绝对(ISO 8601)或相对时间时,"@" 符号就派上用场。
例如,以下查询将为 my_metric
标签返回在 2021-09-01T00:00:00Z 时刻的值:
my_metric @ "2021-09-01T00:00:00Z"
也可以使用相对时间,在这种情况下,结果将以锁定的时间为基础,例如以下查询将返回5分钟前的 my_metric
值:
my_metric @ -5m
这种特性在手动调查和探索时间序列数据时尤其有用,因为它使调查者能够更轻松地观察过去的时间点。 它还使用户能够在PromQL面板中手动对齐查询结果的时间轴,便于进行可视化比较。
需要注意的是,"@" 语法是Prometheus 2.27版本引入的新功能。 在此之前的版本中,用户主要依赖 PromQL 查询中的时间范围选择器以相对时间语法获取指定时间内的数据。
topk(10,
sum by (user) (rate(cortex_distributor_received_samples_total{cluster=~"$cluster", job=~"($namespace)/((distributor|cortex|mimir|mimir-write.*))"}[$__rate_interval] @ end()))
-
sum by (user) (rate(cortex_distributor_received_samples_total{cluster=~"$cluster", job=~"($namespace)/((distributor|cortex|mimir|mimir-write.*))"}[$__rate_interval] @ start()))
)
十、取整相关
ceil(v instant-vector) :四舍五入取整
floor(v instant-vector) :与 ceil() 函数相反,舍弃小数部分取整
ceil函数:
floor函数:
十一、group_left函数
on, ignore, group_left, group_right
基础的模式是这样:
第一个vector的标签:{name, instance, service, method, host},第二个vector的标签{name, instance, service, method}
vector_1 <op> vector_2
这种就会去找两个vector标签和标签值都完全匹配的条目来做op这个操作。
on
vector_1 <op> on({label_list}) vector_2
这个函数会只在前面和后面都出现的标签上面做完全匹配.
vector_1 + on(instance) vector_2:就只会找都有instance标签并且instance的值相同的条目进行计算
ignoring
这个函数跟on相反,忽略对一些标签的匹配
vector_1 + ignoring(instance) vector_2:忽略instance标签,其他的按照默认的情况匹配
group_left
针对第一个vector筛选出来的条目更多,但是两个vector的label可能不匹配,所以需要on或者ignore来限定标签。
左边和右边是1:N的关系
vector_1 + ignore(instance,host) group_left vector_2:这个就代表在忽略instance和host的情况下,左边的vector可能会多出一些条目跟右边的一条条目匹配并作运算。
和张羽确认了下,就是将右边的标签加到左边的,但是一般结合on使用,如下:
group_left作用即是将左右pod相同的情况,把右边的label_qke_cloud_qiyi_domain_app_id和label_qke_cloud_qiyi_domain_app_name两个标签加到左边,加过去之后就可以用sum by求和了
sum by (label_qke_cloud_qiyi_domain_app_id, label_qke_cloud_qiyi_domain_app_name) (rate(http_server_requests_seconds_count{}[5m]) * on (pod) group_left(label_qke_cloud_qiyi_domain_app_id, label_qke_cloud_qiyi_domain_app_name) kube_pod_labels{label_qke_cloud_qiyi_domain_app_name=\"hubble-biz-log\"})
比如:http_server_requests_seconds_count,搜索发现并不含label_qke_cloud_qiyi_domain_app_id
我们再搜索下kube_pod_labels:是包含label_qke_cloud_qiyi_domain_app_id 和 label_qke_cloud_qiyi_domain_app_name两个标签的,所以解释起来就合理了,就是将
还没完,还有多对一的关系:
我们看pod:我们发现,http_server_requests_seconds_count相同的pod是很多的,如下:
再看kube_pod_labels{pod="biz-alarm-query-pod-6888f58676-xqk4j"},如下图所示:pod是唯一的。
所以左边和右边是1:N的关系,所以是将右边的两个指标加到左边所有pod相同的指标中去
验证下:rate(http_server_requests_seconds_count{}[5m]) * on (pod) group_left(label_qke_cloud_qiyi_domain_app_id, label_qke_cloud_qiyi_domain_app_name) kube_pod_labels{label_qke_cloud_qiyi_domain_app_name="hubble-biz-log"}
如下图,标签确实被加进来了
顺便记录下:
kube_pod_labels是kube-state-metrics(kube-state-metrics - 滴滴滴 - 博客园)暴露出来的指标,K8S集群相关的指标是由kube-state-metrics暴露的;
另外,以container_开头的指标是由cAdvisor(集成在kubelet内,用作容器监控)暴露出来的指标
group_right:跟上面的group_left相反。
十二、vector()
我们经常会遇到配置的函数查不到数据,我们又希望提供默认值,这样就有趋势图了,那么我们可以使用vector(0)。
如下:
(sum(rate(robot_engine_exception_total[1m]))/ sum(rate(robot_engine_request_total[1m]))) OR vector(0)
解释:
当(sum(rate(robot_engine_exception_total[1m]))/ sum(rate(robot_engine_request_total[1m])))没有数据时,用0代替。
十三、label_replace
prometheus -label_replace中的细节
首先看下函数label_replace的语法:
label_replace(v instant-vector, dst_label string, replacement string, src_label string, regex string)
v instant-vector 代表要操作的指标,其内包含了我们要替换的label;
dst_label 替换/新增(原始label不存在)label后的label 名字;
replacement 替换/新增label的value,可以是常量,可以是$[0/1/2…]格式的占位符,其后面的序号代表regex的匹配变量位置;
src_label 原始的label;
regex 正则表达式;
上几个例子说明一下replacement的具体含义:
1、replacement定义为常量
原始指标
http_requests_total{code=“400”,handler=“query”,instance=“120.77.65.193:9090”,job=“prometheus”,method=“get”} 9
label_replace函数执行
label_replace(http_requests_total{code=“400”,handler=“query”,instance=“120.77.65.193:9090”,job=“prometheus”,method=“get”}, “instance”, “hello,world”, “method”, “ge.*”)
显示结果:
http_requests_total{code=“400”,handler=“query”,instance=“hello,world”,job=“prometheus”,method=“get”} 9
十四、其它
increase(v range-vector) 函数获取区间向量中的第一个和最后一个样本并返回其增长量,它会在单调性发生变化时(如由于采样目标重启引起的计数器复位)自动中断。
abs(instant-vector) 求瞬时向量绝对值
stddev (标准差)
stdvar (标准差异)
count_values (对 value 进行计数)
quantile (分布统计)
changes(v range-vector) 计算区间向量中每个样本值变化次数,返回的是瞬时向量
clamp_max(v instant-vector, max scalar) 瞬时向量值如果大于max 则值修改为max,否则值不变(用于将向量规范到一个不大于max的区间内)
clamp_min(v instant-vector, min scalar) 同理,将向量规范到一个不小于min值的范围内
day_of_month(v=vector(time()) instant-vector) 返回 1~31 向量所在UTC时间中的所在月份的第几天
day_of_week(v=vector(time()) instant-vector) 函数,返回被给定 UTC 时间所在周的第几天。返回值范围:0~6,0 表示星期天。
days_in_month(v=vector(time()) instant-vector) 函数,返回当月一共有多少天。返回值范围:28~31。
deriv(v range-vector) 的参数是一个区间向量,返回一个瞬时向量。它使用简单的线性回归计算区间向量 v 中各个时间序列的导数。
exp(v instant-vector) 函数,输入一个瞬时向量,返回各个样本值的 e 的指数值,即 e 的 N 次方。当得到一个无穷大的值,显示 +Inf, 反之显示0, e的负数次方无限趋进0。e的空向量指数依然为空向量。
year(v=vector(time()) instant-vector) 函数返回被给定 UTC 时间的当前年份。
hour(v=vector(time()) instant-vector) 函数返回被给定 UTC 时间的当前第几个小时,时间范围:0~23。
minute(v=vector(time()) instant-vector) 函数返回给定 UTC 时间当前小时的第多少分钟。结果范围:0~59。
month(v=vector(time()) instant-vector) 函数返回给定 UTC 时间当前属于第几个月,结果范围:0~12。
label_join(v instant-vector, dst_label string, separator string, src_label_1 string, src_label_2 string, ...) 函数可以将时间序列 v 中多个标签 src_label 的值,通过 separator 作为连接符写入到一个新的标签 dst_label 中。可以有多个 src_label 标签。
1 2 |
|
label_replace(v instant-vector, dst_label string, replacement string, src_label string, regex string) 在原标签中匹配字符,放到目标标签中
ln(v instant-vector) 计算瞬时向量 v 中所有样本数据的自然对数。
1 2 3 4 |
|
log2(v instant-vector) 函数计算瞬时向量 v 中所有样本数据的二进制对数。特殊情况同ln。
log10(v instant-vector) 计算瞬时向量 v 中所有样本数据的十进制对数。特殊情况同ln。
predict_linear(v range-vector, t scalar) 函数可以预测时间序列 v 在 t 秒后的值。它基于简单线性回归的方式,对时间窗口内的样本数据进行统计,从而可以对时间序列的变化趋势做出预测。
resets(v range-vector) 的参数是一个区间向量。对于每个时间序列,它都返回一个计数器重置的次数。两个连续样本之间单调性发生变化被认为是一次计数器重置。
round(v instant-vector, to_nearest=1 scalar) 函数与 ceil 和 floor 函数类似,返回向量中所有样本值的最接近to_nearest值整数倍的值,当to_nearest=1时等价于ceil。
scalar(v instant-vector) 函数返回一个单元素瞬时向量的样本值,当多元素或者没有元素返回Nan。
vector(s scalar) 函数将标量 s 作为没有标签的向量返回(和scalar作用刚好相反)。
sort(v instant-vector) 函数对向量按元素的值进行升序排序。
sort_desc(v instant-vector) 函数对向量按元素的值进行降序排序。
sqrt(v instant-vector) 函数计算向量 v 中所有元素的平方根。
timestamp(v instant-vector) 函数返回向量 v 中的每个样本的时间戳(从 1970-01-01 到现在的秒数)。
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) : 区间向量内每个度量指标的样本数据个数。
到此所有常用函数都介绍完了,还有一些少见的如直方图等请查阅prometheus官网文档。
四、
参考: