mirror of
https://github.com/prometheus/prometheus.git
synced 2025-02-21 03:16:00 -08:00
In histogram_quantile merge buckets with equivalent le values (#5158)
This makes things generally more resilient, and will help with OpenMetrics transitions (and inconsistencies). Signed-off-by: Brian Brazil <brian.brazil@robustperception.io>
This commit is contained in:
parent
a60431f3cd
commit
c66aeb3fff
|
@ -75,16 +75,18 @@ func bucketQuantile(q float64, buckets buckets) float64 {
|
||||||
if q > 1 {
|
if q > 1 {
|
||||||
return math.Inf(+1)
|
return math.Inf(+1)
|
||||||
}
|
}
|
||||||
if len(buckets) < 2 {
|
|
||||||
return math.NaN()
|
|
||||||
}
|
|
||||||
sort.Sort(buckets)
|
sort.Sort(buckets)
|
||||||
if !math.IsInf(buckets[len(buckets)-1].upperBound, +1) {
|
if !math.IsInf(buckets[len(buckets)-1].upperBound, +1) {
|
||||||
return math.NaN()
|
return math.NaN()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buckets = coalesceBuckets(buckets)
|
||||||
ensureMonotonic(buckets)
|
ensureMonotonic(buckets)
|
||||||
|
|
||||||
|
if len(buckets) < 2 {
|
||||||
|
return math.NaN()
|
||||||
|
}
|
||||||
|
|
||||||
rank := q * buckets[len(buckets)-1].count
|
rank := q * buckets[len(buckets)-1].count
|
||||||
b := sort.Search(len(buckets)-1, func(i int) bool { return buckets[i].count >= rank })
|
b := sort.Search(len(buckets)-1, func(i int) bool { return buckets[i].count >= rank })
|
||||||
|
|
||||||
|
@ -107,6 +109,25 @@ func bucketQuantile(q float64, buckets buckets) float64 {
|
||||||
return bucketStart + (bucketEnd-bucketStart)*(rank/count)
|
return bucketStart + (bucketEnd-bucketStart)*(rank/count)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// coalesceBuckets merges buckets with the same upper bound.
|
||||||
|
//
|
||||||
|
// The input buckets must be sorted.
|
||||||
|
func coalesceBuckets(buckets buckets) buckets {
|
||||||
|
last := buckets[0]
|
||||||
|
i := 0
|
||||||
|
for _, b := range buckets[1:] {
|
||||||
|
if b.upperBound == last.upperBound {
|
||||||
|
last.count += b.count
|
||||||
|
} else {
|
||||||
|
buckets[i] = last
|
||||||
|
last = b
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buckets[i] = last
|
||||||
|
return buckets[:i+1]
|
||||||
|
}
|
||||||
|
|
||||||
// The assumption that bucket counts increase monotonically with increasing
|
// The assumption that bucket counts increase monotonically with increasing
|
||||||
// upperBound may be violated during:
|
// upperBound may be violated during:
|
||||||
//
|
//
|
||||||
|
|
22
promql/testdata/histograms.test
vendored
22
promql/testdata/histograms.test
vendored
|
@ -31,6 +31,15 @@ load 5m
|
||||||
request_duration_seconds_bucket{job="job2", instance="ins2", le="0.2"} 0+7x10
|
request_duration_seconds_bucket{job="job2", instance="ins2", le="0.2"} 0+7x10
|
||||||
request_duration_seconds_bucket{job="job2", instance="ins2", le="+Inf"} 0+9x10
|
request_duration_seconds_bucket{job="job2", instance="ins2", le="+Inf"} 0+9x10
|
||||||
|
|
||||||
|
# Different le representations in one histogram.
|
||||||
|
load 5m
|
||||||
|
mixed_bucket{job="job1", instance="ins1", le="0.1"} 0+1x10
|
||||||
|
mixed_bucket{job="job1", instance="ins1", le="0.2"} 0+1x10
|
||||||
|
mixed_bucket{job="job1", instance="ins1", le="2e-1"} 0+1x10
|
||||||
|
mixed_bucket{job="job1", instance="ins1", le="2.0e-1"} 0+1x10
|
||||||
|
mixed_bucket{job="job1", instance="ins1", le="+Inf"} 0+4x10
|
||||||
|
mixed_bucket{job="job1", instance="ins2", le="+inf"} 0+0x10
|
||||||
|
mixed_bucket{job="job1", instance="ins2", le="+Inf"} 0+0x10
|
||||||
|
|
||||||
# Quantile too low.
|
# Quantile too low.
|
||||||
eval instant at 50m histogram_quantile(-0.1, testhistogram_bucket)
|
eval instant at 50m histogram_quantile(-0.1, testhistogram_bucket)
|
||||||
|
@ -157,3 +166,16 @@ load 5m
|
||||||
# Nonmonotonic buckets
|
# Nonmonotonic buckets
|
||||||
eval instant at 50m histogram_quantile(0.99, nonmonotonic_bucket)
|
eval instant at 50m histogram_quantile(0.99, nonmonotonic_bucket)
|
||||||
{} 0.989875
|
{} 0.989875
|
||||||
|
|
||||||
|
# Buckets with different representations of the same upper bound.
|
||||||
|
eval instant at 50m histogram_quantile(0.5, rate(mixed_bucket[5m]))
|
||||||
|
{instance="ins1", job="job1"} 0.15
|
||||||
|
{instance="ins2", job="job1"} NaN
|
||||||
|
|
||||||
|
eval instant at 50m histogram_quantile(0.75, rate(mixed_bucket[5m]))
|
||||||
|
{instance="ins1", job="job1"} 0.2
|
||||||
|
{instance="ins2", job="job1"} NaN
|
||||||
|
|
||||||
|
eval instant at 50m histogram_quantile(1, rate(mixed_bucket[5m]))
|
||||||
|
{instance="ins1", job="job1"} 0.2
|
||||||
|
{instance="ins2", job="job1"} NaN
|
||||||
|
|
Loading…
Reference in a new issue