Prometheus Histogram分位线计算
mufiye 内核新手

Prometheus有四种指标类型,分别是Counter、Gauge、Histogram以及Summary。

其中Counter是一个累加的计数值,Gauge是一个瞬时值,Histogram以及Summary是对一段时间内数值做一个汇总统计,Histogram使用分桶统计指标数值的分布(比如不同耗时的请求,每个耗时区间有多少数量的请求),Summary则是在客户端直接计算得到总和、平均值以及分位线。

分位线(Quantile)是用于将数据分成等量部分的统计量。它的作用是将一个数据集按一定比例分割,并标志这些分割点。比如在可观测领域常用的P99分位线,用在黄金指标的耗时指标中,其的含义就是最慢的那百分之一请求的耗时最小值是多少。Summary的分位线直接在客户端计算,而Histogram的分位线是在服务端进行计算,这里主要讲一下计算的逻辑。

Histogram使用一个个桶来标识不同区间数据的数量,每个桶有两个属性,分别是上界(upperBound)和数量(count),也就是Histogram指标统计的所有数据小于该上界的数量。那么当我们想要求某一个分位线时,比如P99,我们就是求比Histogram中99%的数据都要大的数值,我们可以用百分数去乘以该桶的总数量,也就是比我们要求的值小的数据数量,之后根据该求得的数量rank找到所在桶的位置,之后使用线性插值法求得rank在该桶中大致的位置,也就得到了我们想要的分位数。

1
2
3
4
5
6
7
type bucket struct {
upperBound float64
count float64
}

// buckets implements sort.Interface.
type buckets []bucket
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
func bucketQuantile(q float64, buckets buckets) float64 {
if math.IsNaN(q) {
return math.NaN()
}
if q < 0 {
return math.Inf(-1)
}
if q > 1 {
return math.Inf(+1)
}
slices.SortFunc(buckets, func(a, b bucket) int {
// We don't expect the bucket boundary to be a NaN.
if a.upperBound < b.upperBound {
return -1
}
if a.upperBound > b.upperBound {
return +1
}
return 0
})
if !math.IsInf(buckets[len(buckets)-1].upperBound, +1) {
return math.NaN()
}

buckets = coalesceBuckets(buckets)
ensureMonotonic(buckets)

if len(buckets) < 2 {
return math.NaN()
}
observations := buckets[len(buckets)-1].count
if observations == 0 {
return math.NaN()
}
// 位置 = 百分比 * 总数量
rank := q * observations
// 找到其所在的桶位置
b := sort.Search(len(buckets)-1, func(i int) bool { return buckets[i].count >= rank })

if b == len(buckets)-1 {
return buckets[len(buckets)-2].upperBound
}
if b == 0 && buckets[0].upperBound <= 0 {
return buckets[0].upperBound
}
var (
bucketStart float64
bucketEnd = buckets[b].upperBound
count = buckets[b].count
)
// 使用线性插值法计算在该桶中的估算位置
if b > 0 {
bucketStart = buckets[b-1].upperBound
count -= buckets[b-1].count
rank -= buckets[b-1].count
}
return bucketStart + (bucketEnd-bucketStart)*(rank/count)
}
  • 本文标题:Prometheus Histogram分位线计算
  • 本文作者:mufiye
  • 创建时间:2024-09-21 22:49:07
  • 本文链接:http://mufiye.github.io/2024/09/21/Prometheus-Histogram分位线计算/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
 评论