直方图和摘要是更复杂的指标类型。单个直方图或摘要不仅会创建大量时间序列,而且更难正确使用这些指标类型。本节将帮助您为您的用例选择和配置合适的指标类型。
一些库仅支持两种类型中的一种,或者仅以有限的方式支持摘要(缺乏分位数计算)。
直方图和摘要都对观测值进行采样,通常是请求持续时间或响应大小。它们跟踪观测次数和观测值的总和,使您可以计算观测值的平均值。请注意,观测次数(在 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])
直方图(但不是摘要)的直接用途是计算落入特定观测值桶中的观测值。
您可能有一个 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 表达式进行临时配置。 | 通常不可聚合。 |
请注意表中最后一项的重要性。让我们回到在 300 毫秒内为 95% 的请求提供服务的 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 个百分位数恰好位于我们的 SLO 300 毫秒处。使用直方图,计算值是准确的,因为第 95 个百分位数的值恰好与其中一个桶边界重合。即使是稍微不同的值仍然是准确的,因为相关桶内(人为的)均匀分布正是桶内线性插值所假设的。
现在,摘要报告的分位数的误差变得更有意思了。摘要中分位数的误差在 φ 的维度中配置。在我们的例子中,我们可能配置了 0.95±0.01,即计算出的值将在第 94 个百分位数和第 96 个百分位数之间。在上述分布下,第 94 个分位数为 270 毫秒,第 96 个分位数为 330 毫秒。摘要报告的第 95 个百分位数的计算值可以在 270 毫秒到 330 毫秒之间的任何位置,不幸的是,这正好是明显在 SLO 范围内与明显在 SLO 范围外之间的所有差异。
底线是:如果您使用摘要,您可以在 φ 的维度中控制误差。如果您使用直方图,您可以通过选择适当的桶布局来控制观测值维度的误差。对于广泛的分布,φ 的微小变化会导致观测值的较大偏差。对于尖锐的分布,观测值的很小区间覆盖了 φ 的很大部分区间。
两条经验法则
如果需要聚合,请选择直方图。
否则,如果您了解将要观测到的值的范围和分布,请选择直方图。如果您需要准确的分位数,无论值的范围和分布如何,请选择摘要。
实现它! 欢迎代码贡献。一般来说,我们预计直方图比摘要更迫切需要。直方图在客户端库中也更容易实现,因此我们建议在有疑问时首先实现直方图。
该文档是开源的。请通过提交问题或拉取请求来帮助改进它。