Prometheus guage类型rate(变化率)计算

目录

 

引言

问题场景

尝试解决

deriv函数解析

最终解决

总结与思考


 

引言

        Promethues是k8s以及云原生下的标准监控告警系统,提供了很多内置的函数,功能已经十分强大,但是,依然有一些需求不能直接使用内置函数来解决。比如,Promethues中计算变化率可以使用内置的rate或者irate函数,但是这两个函数只能作用于counter类型,如果是guage类型,则没有同样功能的内置函数来实现。笔者在实际工作中遇到了类似的问题,本文记录了整体的解决过程和思路。

        期望直接看解答的,可以直接查看最下面最终解决部分。

问题场景

        用户有一个qps指标,记录的是当前的瞬时qps,使用的是guage类型。用户侧期望配置一个监控,能够在qps出现剧烈波动的情况下发出告警,具体规则是突增或突降30%以上。

尝试解决

        对于Promethues变化率,百度和google可以搜到很多,不过都是rate的用法。官方文档上也明确说了,rate和irate只适用于counter类的指标。

rate should only be used with counters and native histograms where the components behave like counters.

irate should only be used when graphing volatile, fast-moving counters.

        又google了一下,发现How to calculate the instant rate of a guage metric中指出可以使用deriv函数来解决。

        百度和google查了一圈,除了官方文档中的解释和一些中文翻译,几乎没有deriv函数相关的资料,那么只能实际的测试一把了。

        使用下面的公式:

deriv(sum({__name__=~"current_qps"})[1m])

        得到结果:

5b83740036624dd1bcdf6ed3461acd41.png

        看起来也还比较符合趋势,就没有进行深究,设置了对应的告警策略(加上abs取绝对值):

abs(deriv(sum({__name__=~"current_qps"})[1m])) > 30

        加上告警后,因为触发的比较多,所以对比了计算触发告警两个点之间的差值,发现不够30%,差距较大。

deriv函数解析

        因为监控告警不准,所以要认真解析下deriv函数了。同时,由于网上资源过于稀少,所以只能从源码入手了。

        查看Promethues源码,functions.md中指出:

## `deriv()`

 

`deriv(v range-vector)` calculates the per-second derivative of the time series in a range

vector `v`, using [simple linear regression](https://en.wikipedia.org/wiki/Simple_linear_regression).

The range vector must have at least two samples in order to perform the calculation. When `+Inf` or

`-Inf` are found in the range vector, the slope and offset value calculated will be `NaN`.

 

`deriv` should only be used with gauges.

        deriv实际上是计算了范围向量每秒的导数,根据高中数学知识(已经忘完了,重新百度的)导数是平面上点切线的斜率,因此我理解这个deriv求出的应该是斜率。那具体是怎么计算斜率呢,文档中指出,计算依据的数学方法是简单线性回归:

1a25d7faf98c4b929f27a88fa4c89138.png

        看到这里,因为数学知识的匮乏和长久不用的生疏,盲目相信Stack Overflow文章 的解答,自己直接认为导数==斜率==比率,为了验证自己的想法,继续查看Promethues的源码,看看是如何计算的:

        funcDeriv中首先获取样品值,数据少于2的话直接return,关键的处理步骤是:

slope, _ := linearRegression(samples.Points, samples.Points[0].T)

e6100c80b9bc4d6abb97586ab5dfef17.png

        Matrix的定义:

98284a3884a64cf6a957ba84ab0f57e8.png

        Series的定义:

a6e787f210c04e5da4f530295734eaff.png

         继续查看linearRegression 代码:

26200dac87214fcf94a7617f6255924a.png

        基本上就是简单线性回归求斜率的实现,其中涉及到了一个kahanSumInc函数,这里笔者一开始认为是逻辑处理,后来查询资料发现是一个公共的Kahan求和算法,查询了一下kahan求和算法

2fe093c7354749379aad104921ba4e35.png

        回到Promethues的工程实现:

671601cd2c8440cba254aac17c828894.png         学到这里,也是有所收获,以后如果遇到处理多float类型的加和精度损失问题,可以借鉴与参考,尤其是一些涉及到钱的功能。

        而至于deriv函数,其得出的值确实是导数,或者说是斜率。它可以代表指标变化的加速度,但是无法代表变化率,因此想要求变化率,还得另辟蹊径。

最终解决

        我们知道,变化率=(X2-X1) / X1,对于Promethues的指标来说,我们可以拿到当前的值X2,据我的了解,可能不全面,没有函数和方法能直接拿到前一个时刻X1的值,但是,我们可以通过delta函数来拿到差值,也就是说:

delta=X2-X1

所以:

X1=X2-delta

所以:
变化率=delta / (X2 - delta)

最终的监控指标写法:

1、如果要监控最近两个数据时间点的变化率,类似于irate,使用以下方法:

abs(idelta(sum({__name__=~"current_qps"})[1m]) / (sum({__name__=~"current_qps"})- idelta(sum({__name__=~"current_qps"})[1m]))) > 0.3

2、如果要看1min平均的,类似于rate,使用以下方法:

abs(delta(sum({__name__=~"current_qps"})[1m]) / (sum({__name__=~"current_qps"})- delta(sum({__name__=~"current_qps"})[1m]))) > 0.3

在线上验证了下,数据符合预期。

总结与思考

        遇到问题我们习惯于百度与google,而不是自己分析。google出来的答案不一定是合理的,而且由于大部分是英文的,理解也可能有偏差。因此,对于问题和需求,在google出的资料不是特别符合的情况下,还是要从需求本身出发,转换思维模式,利用手头上有的资源来实现我们的目的。

 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值