Compare commits

...

4 Commits

Author SHA1 Message Date
Zakhar Bessarab
7ccd047e53 app/vmselect/promql: remove duplicated logic of filling NaN values for histograms
Removed logic was used to fill nan values with lower buckets values: [1 2 3 nan nan nan] => [1 2 3 3 3 3].
Since buckets are now fixed from lower ones to upper this happens in the main loop, so there is no need in a second one.

Signed-off-by: Zakhar Bessarab <z.bessarab@victoriametrics.com>
2024-07-03 12:37:48 +04:00
Zakhar Bessarab
d861062769 app/vmselect/promql: update comment to be consistent with an implementation
Signed-off-by: Zakhar Bessarab <z.bessarab@victoriametrics.com>
2024-07-03 12:37:48 +04:00
Zakhar Bessarab
52d7d601fe Update app/vmselect/promql/transform.go
Co-authored-by: Andrii Chubatiuk <andrew.chubatiuk@gmail.com>
2024-07-03 12:37:48 +04:00
Zakhar Bessarab
5c7514134b app/vmselect/promql: propagate lower bucket values when fixing a histogram
In most cases histograms are exposed in sorted manner with lower buckets being first. This means that during scraping buckets with lower bounds have higher chance of being updated earlier than upper ones.

 Previously, values were propagated from upper to lower bounds, which means that in most cases that would produce results higher than expected once all buckets will become updated.
 Propagating from upper bound effectively limits highest value of histogram to the value of previous scrape. Once the data will become consistent in the subsequent evaluation this causes spikes in the result.

 Changing propagation to be from lower to higher buckets reduces value spikes in most cases due to nature of the original inconsistency.

 See: https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4580

Signed-off-by: Zakhar Bessarab <z.bessarab@victoriametrics.com>
2024-07-03 12:37:48 +04:00
3 changed files with 12 additions and 23 deletions

View File

@@ -4471,7 +4471,7 @@ func TestExecSuccess(t *testing.T) {
),0.01)`
r := netstorage.Result{
MetricName: metricNameExpected,
Values: []float64{18.57, 18.57, 18.57, 18.57, 18.57, 18.57},
Values: []float64{30, 30, 30, 30, 30, 30},
Timestamps: timestampsExpected,
}
r.MetricName.Tags = []storage.Tag{{

View File

@@ -1044,29 +1044,18 @@ func fixBrokenBuckets(i int, xss []leTimeseries) {
// Buckets are already sorted by le, so their values must be in ascending order,
// since the next bucket includes all the previous buckets.
// If the next bucket has lower value than the current bucket,
// then the current bucket must be substituted with the next bucket value.
// then the next bucket must be substituted with the current bucket value.
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2819
if len(xss) < 2 {
return
}
// Fill NaN in upper buckets with the first non-NaN value found in lower buckets.
for j := len(xss) - 1; j >= 0; j-- {
// Substitute upper bucket values with lower bucket values if the upper values are NaN
// or are bigger than the lower bucket values.
vNext := xss[0].ts.Values[0]
for j := 1; j < len(xss); j++ {
v := xss[j].ts.Values[i]
if !math.IsNaN(v) {
j++
for j < len(xss) {
xss[j].ts.Values[i] = v
j++
}
break
}
}
// Substitute lower bucket values with upper values if the lower values are NaN
// or are bigger than the upper bucket values.
vNext := xss[len(xss)-1].ts.Values[i]
for j := len(xss) - 2; j >= 0; j-- {
v := xss[j].ts.Values[i]
if math.IsNaN(v) || v > vNext {
if math.IsNaN(v) || vNext > v {
xss[j].ts.Values[i] = vNext
} else {
vNext = v

View File

@@ -32,11 +32,11 @@ func TestFixBrokenBuckets(t *testing.T) {
f(nil, []float64{})
f([]float64{1}, []float64{1})
f([]float64{1, 2}, []float64{1, 2})
f([]float64{2, 1}, []float64{1, 1})
f([]float64{2, 1}, []float64{2, 2})
f([]float64{1, 2, 3, nan, nan}, []float64{1, 2, 3, 3, 3})
f([]float64{5, 1, 2, 3, nan}, []float64{1, 1, 2, 3, 3})
f([]float64{1, 5, 2, nan, 6, 3}, []float64{1, 2, 2, 3, 3, 3})
f([]float64{5, 10, 4, 3}, []float64{3, 3, 3, 3})
f([]float64{5, 1, 2, 3, nan}, []float64{5, 5, 5, 5, 5})
f([]float64{1, 5, 2, nan, 6, 3}, []float64{1, 5, 5, 5, 6, 6})
f([]float64{5, 10, 4, 3}, []float64{5, 10, 10, 10})
}
func TestVmrangeBucketsToLE(t *testing.T) {