VictoriaMetrics/lib/streamaggr/rate.go

116 lines
2.5 KiB
Go
Raw Normal View History

package streamaggr
import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil"
)
func rateInitFn(isAvg bool) aggrValuesInitFn {
return func(values []aggrValue) []aggrValue {
shared := &rateAggrValueShared{
lastValues: make(map[string]rateLastValue),
}
for i := range values {
values[i] = &rateAggrValue{
isAvg: isAvg,
shared: shared,
state: make(map[string]rateAggrValueState),
}
}
return values
}
}
// rateLastValue calculates output=rate_avg and rate_sum, e.g. the average per-second increase rate for counter metrics.
type rateLastValue struct {
value float64
deleteDeadline int64
// prevTimestamp is the timestamp of the last registered sample in the previous aggregation interval
prevTimestamp int64
}
lib/streamaggr: follow-up for 9c3d44c8c961d072f545e5e09f98f99bb7dfb2c0 - Consistently enumerate stream aggregation outputs in alphabetical order across the source code and docs. This should simplify future maintenance of the corresponding code and docs. - Fix the link to `rate_sum()` at `see also` section of `rate_avg()` docs. - Make more clear the docs for `rate_sum()` and `rate_avg()` outputs. - Encapsulate output metric suffix inside rateAggrState. This eliminates possible bugs related to incorrect suffix passing to newRateAggrState(). - Rename rateAggrState.total field to less misleading rateAggrState.increase name, since it calculates counter increase in the current aggregation window. - Set rateLastValueState.prevTimestamp on the first sample in time series instead of the second sample. This makes more clear the code logic. - Move the code for removing outdated entries at rateAggrState into removeOldEntries() function. This make the code logic inside rateAggrState.flushState() more clear. - Do not write output sample with zero value if there are no input series, which could be used for calculating the rate, e.g. if only a single sample is registered for every input series. - Do not take into account input series with a single registered sample when calculating rate_avg(), since this leads to incorrect results. - Move {rate,total}AggrState.flushState() function to the end of rate.go and total.go files, so they look more similar. This shuld simplify future mantenance. Updates https://github.com/VictoriaMetrics/VictoriaMetrics/pull/6243
2024-07-14 15:23:59 +00:00
type rateAggrValueShared struct {
lastValues map[string]rateLastValue
}
type rateAggrValueState struct {
// increase stores cumulative increase for the current time series on the current aggregation interval
increase float64
timestamp int64
}
type rateAggrValue struct {
shared *rateAggrValueShared
state map[string]rateAggrValueState
isAvg bool
}
func (av *rateAggrValue) pushSample(ctx *pushSampleCtx) {
sv := av.state[ctx.inputKey]
inputKey := ctx.inputKey
lv, ok := av.shared.lastValues[ctx.inputKey]
if ok {
if ctx.sample.timestamp < sv.timestamp {
// Skip out of order sample
return
}
if ctx.sample.value >= lv.value {
sv.increase += ctx.sample.value - lv.value
} else {
// counter reset
sv.increase += ctx.sample.value
}
} else {
lv.prevTimestamp = ctx.sample.timestamp
}
lv.value = ctx.sample.value
lv.deleteDeadline = ctx.deleteDeadline
sv.timestamp = ctx.sample.timestamp
inputKey = bytesutil.InternString(inputKey)
av.state[inputKey] = sv
av.shared.lastValues[inputKey] = lv
}
func (av *rateAggrValue) flush(ctx *flushCtx, key string) {
suffix := av.getSuffix()
rate := 0.0
countSeries := 0
lvs := av.shared.lastValues
for lk, lv := range lvs {
if ctx.flushTimestamp > lv.deleteDeadline {
delete(lvs, lk)
continue
}
}
for sk, sv := range av.state {
lv := lvs[sk]
if lv.prevTimestamp == 0 {
continue
}
d := float64(sv.timestamp-lv.prevTimestamp) / 1000
if d > 0 {
rate += sv.increase / d
countSeries++
}
lv.prevTimestamp = sv.timestamp
lvs[sk] = lv
delete(av.state, sk)
}
if countSeries == 0 {
return
}
if av.isAvg {
rate /= float64(countSeries)
}
if rate > 0 {
ctx.appendSeries(key, suffix, rate)
}
}
func (av *rateAggrValue) getSuffix() string {
if av.isAvg {
return "rate_avg"
}
return "rate_sum"
}