prometheus -- rate()与irate()分析与源码

结论

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;

prometheus -- rate()与irate()分析与源码_第1张图片

若要计算一段时间内的结果:

  • 对每个数据点,计算(value - valueBeforeRange)/range;
  • 最终得到一串数据,绘制变化率图形;

prometheus -- rate()与irate()分析与源码_第2张图片

当抓取指标的进程重启时,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.

prometheus -- rate()与irate()分析与源码_第3张图片

由于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...

你可能感兴趣的