注意: 本文档早于原生直方图(作为实验性功能添加到 Prometheus v2.40 中)。一旦原生直方图更接近成为稳定功能,本文档将进行彻底更新。

直方图和摘要

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

库支持

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

某些库只支持两种类型中的一种,或者它们只以有限的方式支持摘要(缺乏 分位数计算)。

观测值的计数和总和

直方图和摘要都对观测值进行采样,通常是请求持续时间或响应大小。它们跟踪观测值的计数 _和_ 观测值的总和,允许您计算观测值的 _平均值_。请注意,观测值的计数(在 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,要求在 300 毫秒内提供 95% 的请求。在这种情况下,配置一个直方图,使其有一个上限为 0.3 秒的范围。然后,您可以直接表达在 300 毫秒内提供的请求的相对数量,并且如果该值降至 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 倍)。例如:目标请求持续时间为 300 毫秒。可容忍的请求持续时间为 1.2 秒。以下表达式得出过去 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% 的请求在 300 毫秒内完成的 SLO。这一次,您不想显示在 300 毫秒内完成的请求百分比,而是要显示第 95 个百分位数,即您已提供 95% 请求的请求持续时间。要做到这一点,您可以配置一个具有 0.95 分位数和(例如)5 分钟衰减时间的摘要,或者配置一个在 300 毫秒标记周围有几个范围的直方图,例如 {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 分钟,您只需调整上面的表达式,而无需重新配置客户端。

分位数估计的误差

分位数,无论是在客户端计算还是在服务器端计算,都是估计的。了解这种估计的误差很重要。

继续上面直方图的示例,假设您的典型请求持续时间几乎都非常接近 220 毫秒,换句话说,如果您能绘制“真实”直方图,您将看到 220 毫秒处有一个非常尖锐的峰值。在上面配置的 Prometheus 直方图指标中,几乎所有观测值,包括第 95 个百分位数,都将落在标记为 {le="0.3"} 的范围内,即从 200 毫秒到 300 毫秒的范围。直方图实现保证真实第 95 个百分位数介于 200 毫秒和 300 毫秒之间。为了返回单个值(而不是一个区间),它应用线性插值,在这种情况下会产生 295 毫秒。计算的分位数给您一种印象,即您即将违反 SLO,但实际上,第 95 个百分位数略高于 220 毫秒,距离您的 SLO 相当远。

我们思考实验的下一步:后端路由的更改将所有请求持续时间增加了固定的 100 毫秒。现在请求持续时间在 320 毫秒处有一个尖峰,几乎所有观察结果都落在 300 毫秒到 450 毫秒的桶中。计算出的第 95 个百分位数为 442.5 毫秒,虽然正确的值接近 320 毫秒。虽然您只稍微超出了您的 SLO,但计算出的第 95 个分位数看起来要糟糕得多。

摘要至少在客户端使用适当的算法(例如 Go 客户端使用的算法)的情况下,在两种情况下都能正确计算出百分位数的值。不幸的是,如果您需要聚合来自多个实例的观察结果,则无法使用摘要。

幸运的是,由于您对桶边界进行了适当的选择,即使在这个观察值分布非常尖锐的构造示例中,直方图也能够正确识别您是否在 SLO 内或外。此外,分位数的实际值越接近我们的 SLO(或者换句话说,我们真正最感兴趣的值),计算出的值就越准确。

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

摘要报告的分位数的误差现在变得更加有趣。摘要中分位数的误差是在 φ 维度上配置的。在我们的例子中,我们可能配置了 0.95±0.01,即计算出的值将在第 94 个百分位数和第 96 个百分位数之间。上述分布的第 94 个分位数为 270 毫秒,第 96 个分位数为 330 毫秒。摘要报告的第 95 个百分位数的计算值可以在 270 毫秒到 330 毫秒之间的任何地方,不幸的是,这完全是明显在 SLO 内与明显在 SLO 外的区别。

底线是:如果您使用摘要,您控制 φ 维度的误差。如果您使用直方图,您通过选择适当的桶布局来控制观察值的误差维度。对于广泛的分布,φ 的微小变化会导致观察值的较大偏差。对于尖锐的分布,观察值的较小间隔会覆盖 φ 的较大间隔。

两条经验法则

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

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

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

实现它!欢迎代码贡献。一般来说,我们预计直方图比摘要更迫切需要。直方图也更容易在客户端库中实现,因此,如果存在疑问,我们建议首先实现直方图。

本文档是 开源 的。请通过提交问题或拉取请求来帮助改进它。