直方图和摘要

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

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

库支持

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

有些库只支持其中一种类型,或者对摘要的支持有限(缺少分位数计算)。

观测值的计数和总和

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

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

  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. 否则,如果您对观测值的范围和分布有了解,请选择直方图。如果您需要精确的分位数,无论值的范围和分布如何,请选择摘要。

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

去实现它!欢迎代码贡献。一般来说,我们预计直方图比摘要更急需。直方图也更容易在客户端库中实现,所以如有疑问,我们建议优先实现直方图。

本页内容