我是否正确理解 Prometheus 的 rate vs increase 功能?

Do I understand Prometheus's rate vs increase functions correctly?

我仔细看了Prometheus documentation,还是有点不清楚,所以来确认下我的理解。

(请注意,为了尽可能简单的示例,我使用了一秒作为抓取间隔、时间范围——即使在实践中不可能)

尽管我们每秒都抓取一个计数器,而计数器的值现在是 30。为此,我们有以下时间序列:

second   counter_value    increase calculated by hand(call it ICH from now)
1             1                    1
2             3                    2
3             6                    3
4             7                    1
5            10                    3
6            14                    4
7            17                    3
8            21                    4
9            25                    4
10           30                    5

我们想运行对该数据集进行一些查询。

1.rate()
官方文档指出:
"rate(v range-vector) : 计算时间序列在范围向量中的每秒平均增长率。"

用外行的术语来说,这意味着我们将获得每秒的增量,给定秒的值将是给定范围内的平均增量?

我的意思是:
rate(counter[1s]): 将匹配 ICH,因为平均值仅根据一个值计算。
rate(counter[2s]): 将从 2 秒内的增量中获取平均值并将其分配给秒
所以在前 2 秒,我们得到了总共 3 的增量,这意味着平均值是 1.5/秒。 最终结果:

second result
1       1,5
2       1,5
3        2
4        2
5       3,5
6       3,5
7       3,5
8       3,5
9       4,5
10      4,5

rate(counter[5s]):将从 5 秒内的增量中获取平均值并将其分配给秒
与 [2s] 相同,但我们根据 5 秒的总增量计算平均值。 最终结果:

second result
1        2
2        2
3        2
4        2
5        2
6        4
7        4
8        4
9        4
10       4

所以时间范围越高,我们得到的结果就越平滑。这些增加的总和将与实际计数器相匹配。

2.increase()
官方文档指出:
“增加(v 范围向量):计算范围向量中时间序列的增加。”

对我来说,这意味着它不会在秒之间分配平均值,而是显示给定范围的单个增量(外推)。
increase(counter[1s]): 在我看来,这将与 ICH 和 1s 的速率匹配,只是因为总范围和速率的基本粒度匹配。
increase(counter[2s]): 前 2 秒给了我们总共 3 的增量,所以 2.seconds会得到3的值等等...

  second result   
    1        3*  
    2        3
    3        4*
    4        4
    5        7*
    6        7
    7        7*
    8        7
    9        9*
    10       9

*在我看来,这些值是指涵盖每一秒的外推值。

我理解得好还是离得远?

在理想情况下(您的样本时间戳恰好在秒,您的规则评估恰好在秒)rate(counter[1s]) 将 return 恰好是您的 ICH 值并且 rate(counter[5s]) 将 return 该 ICH 和前 4 个的平均值。除了第 1 秒的 ICH 是 0,而不是 1,因为没有人知道你的计数器何时为零:也许它在那里递增,也许它昨天递增, 之后一直保持在 1。 (这就是为什么第一次出现值为 1 的计数器时您看不到增加的原因 -- 因为您的代码刚刚创建并递增了它。)

increase(counter[5s]) 正好是 rate(counter[5s]) * 5(而 increase(counter[2s]) 正好是 rate(counter[2s]) * 2)。

现在在现实世界中发生的情况是,您的样本并非每秒都在第二秒收集,规则评估也不会恰好在第二秒发生。因此,如果您有一堆(或多或少)相隔 1 秒的样本,并且您使用 Prometheus 的 rate(counter[1s]),您将不会得到任何输出。这是因为 Prometheus 所做的是获取 1 秒范围 [now() - 1s, now()] 内的所有样本(在绝大多数情况下这将是单个样本),尝试计算速率并失败。

如果您查询 rate(counter[5s]) OTOH,Prometheus 将选择 [now() - 5s, now] 范围内的所有样本(5 个样本,平均覆盖大约 4 秒,比如说 [t1, v1], [t2, v2], [t3, v3], [t4, v4], [t5, v5])和(假设您的计数器不会在间隔内重置)将 return (v5 - v1) / (t5 - t1)。 IE。它实际上计算了 ~4s 而不是 5s 的增长率。

increase(counter[5s]) 将 return (v5 - v1) / (t5 - t1) * 5,所以增加的速度超过 ~4 秒,外推到 5 秒。

由于样本间隔不精确,rateincrease 都经常 return 整数计数器的浮点值(这对 rate 很明显, 但 increase).

** 解释反方向分析问题**

假设我们有

rate(some_metric_name_count [3m]) = 2

这意味着在该时间点计数器每秒增加 2 之前的 3 分钟间隔内,在这 3 分钟之后,该计数器增加了 2*180(秒)= 360。

这也意味着在这种情况下:

increase(some_metric_name_count [3m]) ~ 360

引擎盖下有轻微的近似值,主要针对第一个时间点,因此绝对误差可能为 2,这意味着:

increase(some_metric_name_count [3m]) = 360 +/- 2

并且涵盖从 [358, 362] 开始的间隔,包括间隔的结尾

Prometheus 按以下方式在时间戳 t 计算 rate(counter[d])

  1. 它在时间范围 (t-d ... t] 上为 counter 时间序列选择原始样本。请注意,t-d 时间戳不包含在时间范围内,而 t 时间戳包含在时间范围内。如果所选时间范围包含少于两个原始样本,则 Prometheus return 在时间戳 t.
  2. 处是一个空值(间隙)
  3. 然后计算所选原始样本的增量。通常它被计算为最后一个选择的样本和第一个选择的样本之间的差异。如果 counter 在所选时间范围内重置为零,计算会变得稍微复杂一些。为了清楚起见,让我们跳过这一点。
  4. 然后,如果第一个 and/or 最后一个原始样本的时间戳距离所选时间范围的边界太远,则可以推断出增加的结果。
  5. 然后通过将推断的增长除以 d 来计算比率。

Prometheus 计算 increase(counter[d]) 除最后一步外,其他方法相同。

让我们看几个应用于原始数据的例子:

second   counter_value    increase calculated by hand(call it ICH from now)
1             1                    1
2             3                    2
3             6                    3
4             7                    1
5            10                    3
6            14                    4
7            17                    3
8            21                    4
9            25                    4
10           30                    5
  • rate(counter[1s]) 在任何时间戳 t 都不会 return,因为任何时间范围 (t-1s ... t] 只包含一个原始样本,而 Prometheus需要至少两个样本来计算 rate()increase().

  • 当不应用外推时,rate(counter[2s])increase(counter[2]) 将 return 每个时间戳 t 以下值:

t       counter_value    rate(counter[2s])        increase(counter[2s])
1             1                    -                       -
2             3               (3-1)/2=1.0                3-1=2
3             6               (6-3)/2=1.5                6-3=3
4             7               (7-6)/2=0.5                7-6=1
5            10              (10-7)/2=1.5               10-7=3
6            14             (14-10)/2=2                14-10=4
7            17             (17-14)/2=1.5              17-14=3
8            21             (21-17)/2=2                21-17=4
9            25             (25-21)/2=2                25-21=4
10           30             (30-25)/2=2.5              30-25=5

实际上,由于外推,rate(counter[2s])increase(counter[2s]) 的 Prometheus 结果可能略大,因为所选时间范围内的第一个样本距离时间范围的开始相对较远。

此类计算存在以下问题:

  • Prometheus 可以 return 来自 increase() 时间序列的分数结果,其中仅包含整数值。这是因为外推。例如,Prometheus 可能 return 来自 increase(http_requests_total[5m]).

    的小数结果
  • Prometheus returns 来自 increase(counter[d])rate(counter[d]) 的空结果(也称为间隙),而后视 window d 没有至少包含两个样本 - 请参阅上面的 rate(counter[1s])increase(counter[1s]) 示例。

  • Prometheus 完全错过了 (t-d ... t] 间隔之前的原始样本与该间隔的第一个原始样本之间的增加。这可能会导致计算不准确。例如,increase(counter[1h]) 不等于 sum_over_time(increase(counter[1m])[1h:1m]).

Prometheus 开发人员已意识到这些问题 - 请参阅 this link. These issues are addressed by VictoriaMetrics at MetricsQL query language - see this comment and this article 了解技术细节。