Promql函数rate()和irate()辨析

背景

在 Prometheus 监控系统中,对于 counter 类型的容器常用的求导方式是 rate() 或 irate()。

官网文档中,关于他们不同点的叙述如下:

  • rate should only be used with counters. It is best suited for alerting, and for graphing of slow-moving counters.
  • irate should only be used when graphing volatile, fast-moving counters.

光看这两段文字比较抽象,接下来将通过一些详细的例子来讲述他们的原理与良好实践。

一个幽灵

同一个监控,同一个时间,只是因为 rate 的参数,展示出来的效果截然不同。

image.png

image.png

可以看到,rate[10m] 的图相对来说更加平滑,而 rate[1m] 则充满了波动。

最初我们以为是采样精度太低,按以往的经验 irate 是完全精确的,于是将函数改为了 irate,但是效果更加离谱。

image.png

而且通过其他监控项以及业务实际负载可以知道,真实的情况是类似于 rate[10] 那张图的。

到此时,我还心怀侥幸,认为是 rate 的平滑带来的问题,而随后的情况则更加诡异。

image.png

这是一张两天区间内的 rate[1m],注意到 11 月 1 日的部分、11 月 3 日的部分和上面七天区间的 rate[1m] 的对应部分是完全不同的。而和 rate[10m] 的部分则较为相似。

思索

我们知道,irate 取 counter 最近两个点的差值(在我们集群中,数据点的时间间隔默认是 15s),而 rate[1m] 取 1min 内的平均值。

因为 7day 时间区间拉的太大,导致他们算出来的值只有部分画在了图里(如果 12 小时内只能显示 50 个点,差不多 14 min 一个点),相当于做了一次采样,而采样出来的这些点在 11 日正好都落在了低谷,12日正常,13日落在了低谷。(疑点:按理来说随机采样应该不会发生这种情况,除非是业务的执行周期的波峰波谷正好对上了采样点,然后每次跨天时相位变一下)。

而 rate[10m] 会求 10min 内的平均值,相对来说能代表这个采样区间的平均值,所以更能代表实际情况,也更符合需求。

结论

所以官网文档里的“irate should only be used when graphing volatile, fast-moving counters. ”,我现在的理解是指查看的时间区间较短,比如一小时左右,这个时候画出的图能显示所有的数据点,此时 irate 显示的就是精确值,而 rate 显示的平滑后的值,不能满足需求。

而到了时间尺度极大(几天级甚至更高)的时候,irate 就类似于了随机值,而 rate 更能反应真实的趋势。

如何选择平均区间

平均区间,也就是 rate 函数的参数,而使用为 irate 则代表不进行平均。

很自然想到一个问题,promql 是在代码中就确定好了,如果平均区间太小,可能会在展示区间较大时出现随机抽样;而如果平均区间太大,又会在展示区间较小时过度平滑,无法查看精确值。

好在,grafana 想到了这个问题,可以将平均区间设置为系统变量 __interval(适用于旧版 grafana)或 $__rate_interval(适用于新版 grafana),此时 grafana 会按展示区间的尺度自动设定 promql 中的平滑区间,保证不同需求下的良好行为。

总结

  • 【点在屏幕上的间隔】是提前确定好的,【屏幕尺寸】是固定的,所以【要展示的点数】也是固定的。
  • 在选择了【展示区间】之后,【两个数据点间的时间间隔】就确定好了。
  • 根据这些数据点的时刻,grafana 从 prometheus 中执行对应的 promql,获得数据。

举个例子:

  1. 我的电脑尺寸和 grafana 的设置,一屏共显示 2400 个点,这个是个常数。并且我正好打开了一屏。
  2. 我选择查过去十天的内容,那么每两个数据点之间的时间间隔是 102460/2400=6min.
  3. grafana 选好这些时间点,比如今天凌晨 0:00,0:06,0:12....
  4. grafana 按预设好的 promql 去找 prometheus 计算这些时间点的数据:
    • 假设 promql 里面写着是 rate[1m],那么对于 0:00 的这个查询,prometheus 会返回 [23:59, 0:00] 内的真实数据的平均变化率。对于 0:06 这个查询,prometheus 会返回 [0:05, 0:06] 内的真实数据的平均变化率,依次类推。
      注意到这个时候,[0:00, 0:05] 之间的数据不会对显示结果产生任何影响,这就是抽样所产生的随机性的来源。

    • 假设 promql 里面写着是 rate[6m],那么对于 0:00 的这个查询,prometheus 会返回 [23:54, 0:00] 内的真实数据的平均变化率。对于 0:06 这个查询,prometheus 会返回 [0:00, 0:06] 内的真实数据的平均变化率,依次类推。这个时候所有的数据都会显示在最终的结果中。

    • 假设 promql 里面写着是 rate[24m],那么对于 0:00 的这个查询,prometheus 会返回 [23:36, 0:00] 内的真实数据的平均变化率。对于 0:06 这个查询,prometheus 会返回 [23:42, 0:06] 内的真实数据的平均变化率,依次类推。这个时候所有的数据都会显示在最终的结果中,而且每个数据会被计算多次,相当于额外做了一些平滑。

参考

Why irate from prometheus doesn't capture spikes

# New in Grafana 7.2: $__rate_interval for Prometheus rate queries that just work