本文分享自华为云社区《Prometheus最佳实践 Summary和Histogram》,作者:张俭。
前言
Histogram 和 Summary都是复杂的指标,不仅仅是因为直方图和summary包含了多个时间序列,而且它们还较难使用正确。
观测中的Count和Sum
Histo和summary都是采样观测,典型的采样维度有 响应大小 和 请求时长 。它们跟踪观测值的数量和观测值的总和,从而使您可以计算观测值的平均值。 请注意,观察值的数量(在Prometheus中显示为带有“ _count”后缀的时间序列)本质上是一个计数器(如上所述,它只会增加)。 观测值的总和(以带有_sum后缀的时间序列显示)也可以充当计数器,只要没有负面的观测值即可。 显然,请求持续时间或响应大小永远不会为负。 但是,原则上,您可以使用摘要和直方图来观察负值(例如,摄氏温度)。 在这种情况下,观察值的总和可能会下降,因此您无法再对其应用“ rate()”。
例如,在Histo或者summary上计算5分钟内的平均请求时长,使用如下的PromQL- rate(http_request_duration_seconds_sum[5m])/rate(http_request_duration_seconds_count[5m])
复制代码 Apdex 分数
Histo(而不是summary)的一个直接用途是对落入指定观察值桶中的观察值进行计数。
你可能会有诸如这样的SLO:百分之95的请求都要在300ms内完成返回。在这个场景下,定义一个Histo,定义一个桶的界限为300ms。然后当这个桶的数量小于百分之95的时候就告警。
如下的表达式可以计算上文所述的SLO- sum(rate(http_request_duration_seconds_bucket{le="0.3"}[5m])) by (job)/sum(rate(http_request_duration_seconds_count[5m])) by (job)
复制代码 你可以以一种非常相似的方式估计Apdex分数。以请求时长为例,配置上界为目标请求时长,另一个桶配置为最大忍受时长(通常是目标请求时长的四倍)。例如目标请求时长为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)
复制代码 注: Apdex分数计算- Apdex指数 =(1 × 满意样本 + 0.5 × 容忍样本)÷ 样本总数
复制代码 请注意,我们将两个存储桶的总和相除。 原因是直方图存储桶是[累积](https://en.wikipedia.org/wiki/Histogram#Cumulative_histogram)。 le =“ 0.3”存储桶也包含在le =“ 1.2”存储桶中; 将其除以2即可解决此问题。
该计算与传统的Apdex分数不完全匹配,因为它包括计算中满意和可忍受的部分中的误差。
Quantiles 分位数
你可以使用 summary 和 histogram 来计算 φ-分位数,φ在0到1之间,左右都为闭区间。φ分位数是一个用来计算前φ界限的观测值。换句话说,就是大家平时讲的pxx。p50即是中位数。为了打字方便,后面用 分位数 来行文。
Summary 和 Histogram 的一个区分要点是 summary 在客户端侧计算分位数,然后直接暴露它们,然而 histogram 在客户端侧暴露桶的技术,然后在服务端侧使用 histogram_quantitle() 函数来计算分位数。
HistogramSummary所需的配置合理定义直方图的区间确定好分位数和滑动窗口。其他的分位数和滑动窗口后面是不能计算的客户端性能监控容易,只需要累加Counter即可监控比较昂贵,因为要计算分位数服务端性能服务器必须计算分位数。 如果临时计算的时间过长(例如在大型仪表板中),则可以使用[记录规则]服务端消耗低时间序列的个数(除了_sum 和 _count)每个桶一个时间序列每个分位数一个时间序列分位数误差相关bucket的宽度定义决定了误差分位数是预先定义好的时间滑动窗口的指定分位数使用普罗表达式的实时查询由client预定义好聚合使用普罗表达式的实时查询通常来说不可聚合请注意表中最后一项的重要性。 让我们回到在300毫秒内处理95%请求的SLO。 这次,您不想显示300毫秒内已处理请求的百分比,而是显示第95个百分位数,即您为95%的请求提供服务的请求持续时间。 为此,您可以配置 summary 为0.95位数,衰减时间为5分钟(例如),也可以配置直方图,并在300ms标记附近添加几个存储桶,例如 {le =“ 0.1”},{le =“ 0.2”},{le =“ 0.3”}和{le =“ 0.45”}。 如果您的服务使用多个实例进行复制运行,则将从其中的每个实例收集请求持续时间,然后将所有内容汇总到整体的95%。 但是,从 summary 汇总预先计算的分位数很少是有意义的。 在这种特定情况下,平均分位数会产生统计上无意义的值。- avg(http_request_duration_seconds{quantile="0.95"}) // BAD!
复制代码 使用histograms,使用 histogram_quantile() 可以完全实现聚合。- histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le)) // GOOD.
复制代码 此外,如果您的SLO发生变化并且您现在想要绘制第90个百分位,或者您想将最近10分钟而不是最近5分钟考虑在内,则只需调整上面的表达式即可,而无需重新配置客户端。
分位数估计的误差
分位数,无论是在客户端计算还是在服务端计算,都是一个估计值。理解分位数的误差对我们非常重要。
让我们从上面histogram的例子继续,想象你通常的请求时长基本上都是220ms,或者换句话说,如果你绘制出了正确的histogram,你将会在220ms处看到一个超级大的尖峰。在上面配置的Prometheus直方图度量标准中,几乎所有观察结果以及第95个百分位都将落入标有“ {le =“ 0.3”}”的存储桶中,即从200ms到300ms的存储桶。 直方图实现可确保真实的第95个百分位数在200毫秒至300毫秒之间。 要返回单个值(而不是间隔),它会应用线性插值,在这种情况下将产生295ms。 计算得出的分位数给您的印象是您接近违反SLO,但实际上,第95个百分位数略高于220ms,这是与您的SLO相当舒适的距离。
我们的思想实验的下一步:更改后端路由会为所有请求持续时间增加固定的100ms。 现在,请求持续时间在320毫秒处急剧增加,几乎所有观察结果都会从300毫秒下降到450毫秒。 尽管正确值接近320ms,但第95个百分位数计算为442.5ms。 虽然您仅在SLO之外,但计算得出的第95分位数看起来要差得多。
Summary 就没有上述的问题,除非它在客户端侧使用了估计算法。不幸的是,如果你想要在多个客户端之间聚合,那你无法使用summary
幸运的是,由于你合适的选择了桶的边界,即使在观测值的分布非常锋利的尖刺的这个人为的例子,直方图能够正确识别,如果你是内或您的SLO之外。同样,分位数的实际值越接近我们的SLO(或换句话说,我们实际上最感兴趣的值),计算出的值就越准确。
现在让我们再次修改实验。在新的设置中,请求持续时间的分布在150ms处有一个尖峰,但不像以前那样尖锐,仅占观察值的90%。 10%的观察结果平均分布在150毫秒至450毫秒之间的长尾巴中。根据这种分布,第95个百分位数恰好在我们的300ms SLO处。使用直方图,由于第95个百分位数的值恰好与铲斗边界之一重合,因此计算得出的值是准确的。甚至略有不同的值也将是准确的,因为相关存储区中的(人为)均匀分布正是存储区中线性插值所假定的。
摘要报告的分位数误差现在变得更加有趣。摘要中的分位数误差是在φ维度中配置的。在我们的情况下,我们可能配置为0.95±0.01,即计算出的值将介于94%和96%之间。具有上述分布的第94位为270ms,第96位为330ms。摘要报告的第95个百分位数的计算值可以在270ms和330ms之间的任何位置,很遗憾,这是SLO内明显与SLO外明显之间的所有差异。
最重要的是:如果使用 summary,则可以通过调整维度 来控制误差。如果使用直方图,则可以控制bucket分配 来调整误差(通过选择适当的桶布局)。
分布较宽时,φ的微小变化会导致观测值的较大偏差。分布较锐利时,观测值的较小间隔将覆盖φ的较大间隔。也就是说,整体宽泛的时候,分位数一点点变化,都会导致分位值的较大变化。整体较紧凑的时候,很小的分位值差值,就能覆盖很大的分位数比例。
两条经验法则:
1.如果需要聚合,请选择histogram。
2.否则,如果您对将要观察的值的范围和分布有所了解,请选择histogram。无论值的范围和分布是什么,如果都需要准确的分位数,请选择summary。
点击关注,第一时间了解华为云新鲜技术~
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |