由来
市面上的翻译误导人,压根不是啥平均增长率
,看了下源码和实际算下来让大家好理解
rate
主要代码是在 https://github.com/prometheus/prometheus/blob/master/promql/functions.go 的extrapolatedRate
和 funcRate
,funcRate为
1 2 3
| func funcRate(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector { return extrapolatedRate(vals, args, enh, true, true) }
|
它的前后还有funcDelta
和funcIncrease
对应promql的delta
和increase
,这俩函数内部都是调用的extrapolatedRate
,主要区别是通过向extrapolatedRate
函数传递最后的两个布尔标志位的差异,来在extrapolatedRate
内部进行差异化计算,也就是说rate
、delta
和increase
的部分数学计算逻辑是一样的。
funcRate
里extrapolatedRate
最后俩实参格式为isCounter bool, isRate bool
,所以rate
只能用在counter
的 metrics 类型上进行计算。
数据点的选取
先看这段代码
1 2 3 4 5 6 7 8 9 10 11
| var ( counterCorrection float64 lastValue float64 ) for _, sample := range samples.Points { if isCounter && sample.V < lastValue { counterCorrection += lastValue } lastValue = sample.V } resultValue := lastValue - samples.Points[0].V + counterCorrection
|
counterCorrection是字面意思修正数值,counter会reset,例如exporter重启了。例如60秒内有下面6数值,在第四个数字后面发生了重置
2小于lastValue 8,所以counterCorrection = 8
最后的 resultValue = 4 + 8 - 2
,当然,重置的情况很少,这里如果不重置用数据2 4 6 8 10 12
算就是最后一个值减去第一个值resultValue = 12 - 2 + 0
和重置算得一样
计算的算式
是结果除以时间的秒数
1 2 3
| if isRate { resultValue = resultValue / ms.Range.Seconds() }
|
对比下irate
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| lastSample := samples.Points[len(samples.Points)-1]
previousSample := samples.Points[len(samples.Points)-2]
var resultValue float64 if isRate && lastSample.V < previousSample.V { resultValue = lastSample.V } else { resultValue = lastSample.V - previousSample.V }
sampledInterval := lastSample.T - previousSample.T if sampledInterval == 0 { return out }
if isRate { resultValue /= float64(sampledInterval) / 1000 }
|
结论
官方文档和市面上的 gitbook 都是把rate
翻译成增长率
是错误的,应该是平均每秒增长了多少数值
。按照实践来算下,同时查询node_time_seconds[1m]
和rate(node_time_seconds[1m])
。我们手动计算下看看是否和rate的结果一致
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| $ node_time_seconds[1m] node_time_seconds{instance="exporter:9100",job="node-resources"} 1596077182.3093214 @1596077182.307 // 第一个点 1596077192.3132203 @1596077192.307 1596077202.311446 @1596077202.307 1596077212.309673 @1596077212.307 1596077222.316771 @1596077222.307 1596077232.3151288 @1596077232.307 // 最后一个点 node_time_seconds{instance="10.0.23.29:9100",job="node-resources"} 1596077178.6314309 @1596077178.633 // 第一个点 1596077188.6312084 @1596077188.633 1596077198.633293 @1596077198.634 1596077208.6332283 @1596077208.634 1596077218.6320524 @1596077218.633 1596077228.635078 @1596077228.633 // 最后一个点
$ rate(node_time_seconds[1m]) {instance="exporter:9100",job="node-resources"} 1.0001161479949952 {instance="10.0.23.29:9100",job="node-resources"} 1.0000729417800902
|
先用10.0.23.29
这个 instance 算,
1 2 3 4
| (1596077228.635078 - 1596077178.6314309) / (1596077228.633 - 1596077178.633) // web上的时间是秒数的,go的time是多了三个单位,所以代码里/1000转换成秒这里不需要除以1000 上面式子左边和右边算是下面结果: 50.003647089 / 50 = 1.00007294178
|
谷歌搜的在线计算器算的(比windows的calc精度高一些),由于是float64,所以精度丢失了一些。结果一样。再算下另一个 instance
1 2 3
| (1596077232.3151288 - 1596077182.3093214) / (1596077232.307 - 1596077182.307) 50.0058073997 / 50 = 1.00011614799
|
increase
是最后一个点减去第一个点,不除以秒数。所以在 counter 没发生重置情况下,下面两个是相等的
1
| increase(node_time_seconds[1m]) / 60 == rate(node_time_seconds[1m])
|