请参与 Prometheus 用户调研(2026 年 3 月版) ,帮助社区确定未来开发工作的优先级!

直方图与摘要

注意本文档在原生直方图(Prometheus v2.40 中作为实验性功能引入,并在 v3.8 中趋于稳定)之前编写。我们的意图是在可预见的未来对本文档进行全面更新。

直方图和摘要是更为复杂的指标类型。单个直方图或摘要不仅会创建大量的时间序列,而且这些指标类型也更难正确使用。本节旨在帮助您针对特定用例选择并配置合适的指标类型。

库支持

首先,请检查相关库对直方图摘要的支持情况。

一些库仅支持其中一种类型,或者仅以有限的方式支持摘要(缺少分位数计算功能)。

观测值的计数与总和

直方图和摘要都会对观测值进行采样,通常是请求持续时间或响应大小。它们追踪观测值的数量以及观测值的总和,使您可以计算观测值的平均值。请注意,观测值的数量(在 Prometheus 中显示为带有 _count 后缀的时间序列)本质上是一个计数器(如上所述,它只会增加)。只要没有负的观测值,观测值的总和(显示为带有 _sum 后缀的时间序列)也表现得像一个计数器。显然,请求持续时间或响应大小永远不会是负数。但原则上,您可以使用摘要和直方图来观测负值(例如摄氏温度)。在这种情况下,观测值的总和可能会下降,因此您不能再对它应用 rate() 函数。在那些需要应用 rate() 却无法避免负观测值的极少数情况下,您可以使用两个单独的摘要(一个用于正观测值,一个用于负观测值,后者使用相反的符号),然后使用适当的 PromQL 表达式将结果组合起来。

若要计算过去 5 分钟内来自名为 http_request_duration_seconds 的直方图或摘要的平均请求持续时间,请使用以下表达式

  rate(http_request_duration_seconds_sum[5m])
/
  rate(http_request_duration_seconds_count[5m])

Apdex 分数

直方图(而不是摘要)的一个直接用途是统计落在特定观测值区间(桶)内的观测数量。

您可能有一个 SLO,即 95% 的请求在 300ms 内完成。在这种情况下,请配置一个上限为 0.3 秒的直方图桶。这样,您可以直接表示在 300ms 内完成的请求的相对比例,并在数值跌至 0.95 以下时轻松发出告警。以下表达式通过作业计算过去 5 分钟内完成的请求。请求持续时间是通过名为 http_request_duration_seconds 的直方图收集的。

  sum(rate(http_request_duration_seconds_bucket{le="0.3"}[5m])) by (job)
/
  sum(rate(http_request_duration_seconds_count[5m])) by (job)

您可以以类似的方式近似计算众所周知的Apdex 分数 。配置一个以目标请求持续时间为上限的桶,以及另一个以可容忍的请求持续时间(通常为目标请求持续时间的 4 倍)为上限的桶。示例:目标请求持续时间为 300ms,可容忍的请求持续时间为 1.2s。以下表达式得出每个作业在过去 5 分钟内的 Apdex 分数

(
  sum(rate(http_request_duration_seconds_bucket{le="0.3"}[5m])) by (job)
+
  sum(rate(http_request_duration_seconds_bucket{le="1.2"}[5m])) by (job)
) / 2 / sum(rate(http_request_duration_seconds_count[5m])) by (job)

请注意,我们对两个桶的总和进行了除法运算。原因是直方图桶是累积的 le="0.3" 的桶也包含在 le="1.2" 的桶中;除以 2 修正了这一点。

该计算与传统的 Apdex 分数并不完全匹配,因为它在计算的满意和可容忍部分中包含了错误。

分位数

您可以同时使用摘要和直方图来计算所谓的 φ-分位数,其中 0 ≤ φ ≤ 1。φ-分位数是指在 N 个观测值中排名第 φ*N 的观测值。φ-分位数的示例:0.5-分位数称为中位数,0.95-分位数是第 95 百分位数。

摘要和直方图之间的根本区别在于:摘要在客户端计算流式 φ-分位数并直接暴露它们,而直方图暴露的是桶装观测计数,计算桶中的分位数则发生在服务器端,使用 histogram_quantile() 函数

这两种方法有许多不同的影响

直方图摘要
所需的配置选择适合观测值预期范围的桶。选择所需的 φ-分位数和滑动窗口。其他 φ-分位数和滑动窗口无法在事后计算。
客户端性能观测成本非常低,因为它们只需要增加计数器。由于流式分位数计算,观测成本较高。
服务器性能服务器必须计算分位数。如果特定计算花费时间过长(例如在大型仪表盘中),您可以使用记录规则服务器端成本较低。
时间序列数量(除 _sum_count 系列外)每个配置的桶对应一个时间序列。每个配置的分位数对应一个时间序列。
分位数误差(详情见下文)在观测值维度上的误差受相关桶宽度的限制。在 φ 维度上的误差受可配置值的限制。
φ-分位数和滑动时间窗口的指定使用 Prometheus 表达式进行即席查询。由客户端预配置。
聚合使用 Prometheus 表达式进行即席查询。通常不可聚合 

请注意表中最后一项的重要性。让我们回到“95% 的请求在 300ms 内完成”的 SLO。这一次,您不想显示在 300ms 内完成的请求比例,而是显示第 95 百分位数,即您已服务 95% 请求的持续时间阈值。为此,您可以配置一个带有 0.95-分位数和(例如)5 分钟衰减时间的摘要,或者配置一个在 300ms 标记周围有几个桶(例如 {le="0.1"}, {le="0.2"}, {le="0.3"}, 和 {le="0.45"})的直方图。如果您的服务以多个副本运行,您将从每一个副本收集请求持续时间,然后希望将所有内容聚合为总体的第 95 百分位数。然而,聚合来自摘要的预计算分位数几乎没有意义。在这种特定情况下,平均分位数会产生统计上无意义的数值。

avg(http_request_duration_seconds{quantile="0.95"}) // BAD!

使用直方图,通过 histogram_quantile() 函数可以完美实现聚合。

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

此外,如果您的 SLO 发生变化,现在想绘制第 90 百分位数,或者想考虑过去 10 分钟而不是 5 分钟的情况,只需调整上述表达式,而无需重新配置客户端。

分位数估计的误差

无论是客户端还是服务器端计算,分位数都是估计值。理解这种估计的误差非常重要。

继续上述直方图的示例,假设您通常的请求持续时间几乎都非常接近 220ms,换句话说,如果您能绘制出“真实”的直方图,您会看到 220ms 处有一个非常尖锐的峰值。在如上配置的 Prometheus 直方图指标中,几乎所有的观测值,以及第 95 百分位数,都会落在标记为 {le="0.3"} 的桶中,即 200ms 到 300ms 的桶。直方图实现保证了真正的第 95 百分位数在 200ms 到 300ms 之间。为了返回单个值(而不是区间),它应用线性插值,在本例中得出 295ms。计算出的分位数给您一种即将违反 SLO 的印象,但实际上,第 95 百分位数仅比 220ms 高出一点点,与您的 SLO 之间有相当舒适的距离。

我们的思维实验中的下一步:后端路由的改变为所有请求持续时间增加了 100ms 的固定值。现在,请求持续时间的尖峰出现在 320ms,几乎所有的观测值都将落在 300ms 到 450ms 的桶中。计算出的第 95 百分位数为 442.5ms,尽管正确值接近 320ms。虽然您仅有一点点超出 SLO,但计算出的第 95 分位数看起来要糟糕得多。

摘要在两种情况下都能毫无问题地计算出正确的分位数,前提是它在客户端使用了合适的算法(例如 Go 客户端所使用的算法 )。遗憾的是,如果您需要从多个实例聚合观测值,则无法使用摘要。

幸运的是,由于您对桶边界进行了合理的选择,即使在这个观测值分布极其尖锐的假设实验中,直方图也能够正确识别您是否在 SLO 之内或之外。此外,分位数的实际值越接近我们的 SLO(即我们最感兴趣的值),计算出的值就越准确。

让我们再修改一次实验。在新设置中,请求持续时间的分布在 150ms 处有一个峰值,但不如之前尖锐,仅包含 90% 的观测值。10% 的观测值在 150ms 到 450ms 之间的长尾中均匀分布。在这种分布下,第 95 百分位数恰好在我们的 300ms SLO 处。对于直方图,计算出的值是准确的,因为第 95 百分位数的值恰好与其中一个桶边界重合。即使略有不同的值仍然是准确的,因为相关桶内的(假设的)均匀分布正是桶内线性插值所基于的假设。

摘要报告的分位数的误差现在变得更有趣了。摘要中的分位数误差是在 φ 维度上配置的。在本例中,我们可能配置了 0.95±0.01,即计算出的值将在第 94 到 96 百分位数之间。在上述分布下,第 94 分位数为 270ms,第 96 分位数为 330ms。摘要报告的第 95 百分位数的计算值可以在 270ms 到 330ms 之间的任何位置,不幸的是,这涵盖了从明确在 SLO 之内到明确在 SLO 之外的所有差异。

底线是:如果您使用摘要,则控制 φ 维度上的误差;如果您使用直方图,则控制观测值维度上的误差(通过选择合适的桶布局)。在宽分布中,φ 的微小变化会导致观测值的大偏差。在尖锐分布中,一小段观测值覆盖了很大一部分的 φ。

两个经验法则

  1. 如果您需要进行聚合,请选择直方图。

  2. 否则,如果您对观测值的范围和分布有一定了解,请选择直方图。如果您需要精确的分位数,无论数值范围和分布如何,请选择摘要。

如果我的客户端库不支持我需要的指标类型,我该怎么办?

去实现它!我们欢迎代码贡献。总的来说,我们认为直方图比摘要更迫切需要。直方图在客户端库中也更容易实现,因此如果难以抉择,建议优先实现直方图。

本页内容