基于Prometheus中的速率理解histogram_quantile

24

根据Prometheus文档,要使用直方图指标获得95分位数,可以使用以下查询:

histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))

来源:https://prometheus.io/docs/practices/histograms/#quantiles

由于直方图的每个桶都是一个计数器,因此我们可以计算每个桶的速率,例如:

范围向量中时间序列每秒的平均增长速率。

请参阅:https://prometheus.io/docs/prometheus/latest/querying/functions/#rate

因此,例如,如果bucket value[t-5m]=100且bucket value[t]=200,则bucket rate[t]=(200-100)/(10*60)=0.167

最后,最令人困惑的部分是如何使用histogram_quantile函数知道所有桶速率的情况下为给定指标查找95th百分位数?

是否有任何代码或算法可以让我更好地理解它?


1
你可以参考我在这里的回复。 - howardxking
5个回答

38
一个具体的例子可以很好地解释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=10msbucket=+Infrate_xxx(t)的第95%项。而95%在这里意味着9500th,因为我们总共有10000项(10000*0.95)。
从上面的表格中,bucket=500ms之前有9300 = 3000+3000+1500+1000+800项。

所以9500th项是bucket=500msrange=300~500ms)中的第200项(9500-9300),其中有400项。

Prometheus假设桶中的项均匀地分布在线性模式下。
bucket=500ms200th项的度量值为400ms = 300+(500-300)*(200/400)

也就是说,95%的响应时间为400ms

在使用直方图类型的度量时,请注意以下几点:

  • 度量标准应该具有计数器(COUNTER)的性质;
  • 用于分位数计算的系列应始终定义标签le
  • 特定桶中的项(数据)以线性模式均匀分布(例如:300~500毫秒)。

Prometheus至少做了这个假设。

  • 分位数计算需要将桶按某种升序/降序排序(例如:1ms < 5ms < 10ms < ...);
  • histogram_quantile的结果是一个近似值;

备注:
由于“特定桶中的项(数据)以线性模式均匀分布”的假设,指标值并不总是准确的

比如,实际情况下(例如来自nginx访问日志),bucket=500msrange=300~500ms)的最大持续时间为310ms,但是通过上述设置,我们将从histogram_quantile得到400ms,这有时令人困惑。

桶距越小,“近似值”的准确性就越高。
因此,请设置适合您需求的桶距。


也许你可以使用浮点数来表示 rate_xxx(t) 更加真实,因为 rate 的结果是时间的分母,例如 5 * 60。 - Djvu

3
你可以参考我在这里的回复。
实际上,rate()函数只用于指定时间窗口,分母对百分位数值的计算没有影响。

正如@ospider在下面所说,rate()也可以正确处理计数器重置。increase()也可以使用。 - AnotherParker

3
我相信这里是prometheus中的代码。 总体思路是使用桶中的数据来推断/近似分位数。 Elasticsearch在其滚动聚合能力中也做了类似的事情(但不同/简单得多)。 "Original Answer"翻译成"最初的回答"。

0
你需要使用 reset,因为计数器可以被重置,rate 自动考虑重置,并为每秒钟给出正确的计数。只要记得在使用计数器之前始终使用速率即可。

0
这个主题在Prometheus文档中有一个相当详细的解释。链接是指“分位数估计错误”部分,但我建议阅读整个页面。
它解释说,用这种方式计算的分位数实际上并没有真正的意义,更好地说,它们对真实情况进行了歪曲,并可能引导您做出错误的决策。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接