prometheus的rate与irate内部是如何计算的
source link: https://zhangguanzhang.github.io/2020/07/30/prometheus-rate-and-irate/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
市面上的翻译误导人,压根不是啥平均增长率
,看了下源码和实际算下来让大家好理解
主要代码是在 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数值,在第四个数字后面发生了重置
1
2 4 6 8 2 4
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 {
// counter重置则取最后一个值.
resultValue = lastSample.V
} else {
// 最后一个点数值 - 倒数第二个数值
resultValue = lastSample.V - previousSample.V
}
// 最后两个点的时间间隔
sampledInterval := lastSample.T - previousSample.T
if sampledInterval == 0 {
// Avoid dividing by 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])
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK