一个具体的例子可以很好地解释
histogram_quantile
。
假设:
- 仅有一个系列(series),简单起见。
- 对于度量标准
http_request_duration_seconds
有10个桶(buckets)。
-
10ms、50ms、100ms、200ms、300ms、500ms、1s、2s、3s、5s
-
http_request_duration_seconds
是计数器类型的度量标准。
- 我们至少有两次针对该系列的抓取记录,每次覆盖5分钟,以便使用
rate()
计算每个桶的
quantity
。
-
rate_xxx(t) = (value_xxx[t]-value_xxx[t-5m]) / (5m*60)
是[t-5m,t]
时间段内item quantity
- 在这里,我们看到了2个样本(
value(t)
和
value(t-5m)
)。
- 记录了
10000
个HTTP请求持续时间(
items
),即
10000 = rate_10ms(t) + rate_50ms(t) + rate_100ms(t) + ... + rate_5s(t)
。
桶(毫秒) |
10毫秒 |
50毫秒 |
100毫秒 |
200毫秒 |
300毫秒 |
500毫秒 |
1秒 |
2秒 |
3秒 |
5秒 |
+Inf |
区间 |
~10毫秒 |
10~50毫秒 |
50~100毫秒 |
100~200毫秒 |
200~300毫秒 |
300~500毫秒 |
500毫秒~1秒 |
1~2秒 |
2秒~3秒 |
3~5秒 |
5秒~ |
rate_xxx(t) |
3000 |
3000 |
1500 |
1000 |
800 |
400 |
200 |
40 |
30 |
5 |
5 |
桶(bucket)是直方图的精髓。我们只需要rate_xxx(t)
中的10个数字就可以进行分位数计算。
让我们仔细看一下这个表达式(为简单起见,省略了类似sum()
的聚合)
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))
实际上我们正在寻找bucket=10ms
到bucket=+Inf
中rate_xxx(t)
的第95%
项。而95%
在这里意味着9500th
,因为我们总共有10000
项(10000*0.95
)。
从上面的表格中,bucket=500ms
之前有9300 = 3000+3000+1500+1000+800
项。
所以9500th
项是bucket=500ms
(range=300~500ms
)中的第200
项(9500-9300
),其中有400
项。
Prometheus假设桶中的项均匀地分布在线性模式下。
bucket=500ms
中200th
项的度量值为400ms = 300+(500-300)*(200/400)
也就是说,95%
的响应时间为400ms
。
在使用直方图类型的度量时,请注意以下几点:
- 度量标准应该具有计数器(COUNTER)的性质;
- 用于分位数计算的系列应始终定义标签
le
;
- 特定桶中的项(数据)以线性模式均匀分布(例如:300~500毫秒)。
Prometheus至少做了这个假设。
- 分位数计算需要将桶按某种升序/降序排序(例如:1ms < 5ms < 10ms < ...);
histogram_quantile
的结果是一个近似值;
备注:
由于“特定桶中的项(数据)以线性模式均匀分布”的假设,指标值并不总是准确的
。
比如,实际情况下(例如来自nginx访问日志),bucket=500ms
(range=300~500ms
)的最大持续时间为310ms
,但是通过上述设置,我们将从histogram_quantile
得到400ms
,这有时令人困惑。
桶距越小,“近似值”的准确性就越高。
因此,请设置适合您需求的桶距。