论断
rate 与 irate 都能够计算 counter 的变化率。
区别:
- rate 计算指定工夫范畴内:增量 / 工夫范畴;
- irate 计算指定工夫范畴内:最近两个点的增量 / 最近两个点的时间差;
场景:
- irate 适宜计算疾速变动的 counter,它能够反映出 counter 的疾速变动;
- rate 适宜计算迟缓变动的 counter,它用平均值将峰值削平了(长尾效应);
rate()函数详解
计算 demo_api_request_duration_seconds_count 最近 1min 的每秒变化率:
rate(demo_api_request_duration_seconds_count[1m])
计算方法:
- 取工夫范畴内的 firstValue 和 lastValue;
- 变化率 = (lastValue – firstValue) / Range;
若要计算一段时间内的后果:
- 对每个数据点,计算(value – valueBeforeRange)/range;
- 最终失去一串数据,绘制变化率图形;
当抓取指标的过程重启时,counter 可能会重置为 0,rate()认为指标值只有缩小了就认为被重置了,而后它会主动进行调整。
rate()源码剖析
//promql/functions.go
// FunctionCalls is a list of all functions supported by PromQL, including their types.
var FunctionCalls = map[string]FunctionCall{
......
"rate": funcRate,
}
// === rate(node parser.ValueTypeMatrix) Vector ===
func funcRate(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {return extrapolatedRate(vals, args, enh, true, true)
}
具体计算过程:(略去了主动调整的逻辑)
func extrapolatedRate(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper, isCounter bool, isRate bool) Vector {ms := args[0].(*parser.MatrixSelector)
var (samples = vals[0].(Matrix)[0]
lastValue float64
)
for _, sample := range samples.Points {
......
lastValue = sample.V
}
resultValue := lastValue - samples.Points[0].V
if isRate {resultValue = resultValue / ms.Range.Seconds()
}
......
}
irate()函数详解
应用 rate 计算疾速变动的样本均匀增长率时,容易陷入 长尾问题 ,因为它用平均值将峰值削平了,无奈反映工夫窗口内样本数据的疾速变动。
与 rate 相似,irate 同样能够计算 counter 的均匀增长率,但其反映出的是 刹时增长率。
irate 计算增长率时,应用指定工夫范畴内的最初两个样本数据:
// 官网 doc 的形容
irate(v range-vector) calculates the per-second instant rate of increase of the time series in the range vector.
This is based on the last two data points.
Breaks in monotonicity (such as counter resets due to target restarts) are automatically adjusted for.
因为 rate()提供更平滑的后果,因而在长期趋势剖析或告警中更举荐 rate(),当迅速产生一个短暂的峰值,不应该触发告警。
irate()源码剖析
//promql/functions.go
// FunctionCalls is a list of all functions supported by PromQL, including their types.
var FunctionCalls = map[string]FunctionCall{
......
"irate": funcIrate,
}
// === irate(node parser.ValueTypeMatrix) Vector ===
func funcIrate(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {return instantValue(vals, enh.out, true)
}
具体计算过程:
func instantValue(vals []parser.Value, out Vector, isRate bool) Vector {samples := vals[0].(Matrix)[0]
lastSample := samples.Points[len(samples.Points)-1] // 最初一个点
previousSample := samples.Points[len(samples.Points)-2] // 前一个点
var resultValue float64
if isRate && lastSample.V < previousSample.V {
// Counter reset.
resultValue = lastSample.V
} else {resultValue = lastSample.V - previousSample.V}
sampledInterval := lastSample.T - previousSample.T
if isRate {
// Convert to per-second.
resultValue /= float64(sampledInterval) / 1000
}
}
参考:
1.https://prometheus.io/docs/pr…
2.https://prometheus.io/docs/pr…
3.https://mp.weixin.qq.com/s/7z…