prometheus -- rate()与irate()分析与源码
结论
rate与irate都可以计算counter的变化率。
区别:
- rate计算指定时间范围内:增量/时间范围;
- irate计算指定时间范围内:最近两个点的增量/最近两个点的时间差;
- irate适合计算快速变化的counter,它可以反映出counter的快速变化;
- rate适合计算缓慢变化的counter,它用平均值将峰值削平了(长尾效应);
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]
lastValuefloat64
)
for _, sample := range samples.Points {
......
lastValue = https://www.it610.com/article/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 = https://www.it610.com/article/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...
推荐阅读
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- Docker应用:容器间通信与Mariadb数据库主从复制
- 《真与假的困惑》???|《真与假的困惑》??? ——致良知是一种伟大的力量
- 第326天
- Shell-Bash变量与运算符
- 深入理解Go之generate
- 逻辑回归的理解与python示例
- Guava|Guava RateLimiter与限流算法
- 我和你之前距离
- CGI,FastCGI,PHP-CGI与PHP-FPM