Prometheus 中的 increase() 有时会使值加倍:如何避免?
increase() in Prometheus sometimes doubles values: how to avoid?
我发现对于一些图表,我从普罗米修斯那里得到了双精度值,而应该只是一个:
我使用的查询:
increase(signups_count[4m])
抓取间隔设置为 2 分钟。
如果我查询实际存储的数据:
curl -gs 'localhost:9090/api/v1/query?query=(signups_count[1h])'
"values":[
[1515721365.194, "579"],
[1515721485.194, "579"],
[1515721605.194, "580"],
[1515721725.194, "580"],
[1515721845.194, "580"],
[1515721965.194, "580"],
[1515722085.194, "580"],
[1515722205.194, "581"],
[1515722325.194, "581"],
[1515722445.194, "581"],
[1515722565.194, "581"]
],
我看到只有两次增加。事实上,如果我查询这些时间,我会看到预期的结果:
curl -gs 'localhost:9090/api/v1/query_range?step=4m&query=increase(signups_count[4m])&start=1515721965.194&end=1515722565.194'
"values": [
[1515721965.194, "0"],
[1515722205.194, "1"],
[1515722445.194, "0"]
],
但是 Grafana(和 GUI 中的 Prometheus)倾向于在查询中设置不同的 step
,对于不熟悉 Prometheus 内部工作原理的人来说,我得到了非常意外的结果。
curl -gs 'localhost:9090/api/v1/query_range?step=15&query=increase(signups_count[4m])&start=1515721965.194&end=1515722565.194'
... skip ...
[1515722190.194, "0"],
[1515722205.194, "1"],
[1515722220.194, "2"],
[1515722235.194, "2"],
... skip ...
知道 increase()
只是 ,我想这就是在这种情况下它应该如何工作。
如何避免这种情况?我如何让 Prometheus/Grafana 在大多数情况下显示一个对一个,两个对两个?除了增加刮擦间隔(这将是我最后的手段)。
我了解普罗米修斯 isn't an exact sort of tool,所以如果我不是一直都有一个好号码,但大多数时候都很好,那对我来说很好。
我还缺少什么?
这被称为 aliasing,是信号处理中的一个基本问题。您可以通过提高采样率来稍微改善这一点,4m 范围对于 2m 范围来说有点短。尝试 10 米范围。
这里例如在 1515722220 执行的查询只看到 580@1515722085.194 和 581@1515722205.194 样本。在 2 分钟内增加了 1,在 4 分钟内推断增加了 2 - 这符合预期。
任何基于指标的监控系统都会有类似的工件,如果你想要 100% 的准确性,你需要日志。
increase()
将始终(大约)使您的设置实际增加一倍。
原因是(按照目前的实施):
increase()
是(如您观察到的)rate()
的语法糖,即它是 return 乘以 rate()
的值乘以秒数在你指定的范围内。在您的情况下,它是 rate() * 240
.
rate()
在其计算中使用外推法。在绝大多数情况下,4 分钟的范围将 return 恰好 2 个数据点,几乎恰好相隔 2 分钟。然后将速率计算为最后一个和第一个之间的差异(即您的案例中的 2 点)除以 2 点的时间差(在 99.99% 的案例中约为 120 秒)乘以您请求的范围(恰好 240 秒) ).因此,如果两点之间的增幅为零,则利率为零。如果 2 点之间的增量为 1.0
,则计算出的 rate()
将接近 2.0 / 240
,因此,increase()
将为 2.0
。
这种方法在计数器平稳增加时效果很好(例如,如果您每 2 分钟有或多或少固定的注册数量)。但是对于一个很少增加的计数器(就像你的注册计数器一样)或者一个尖锐的计数器(比如 CPU 使用率)你会得到奇怪的高估(比如你看到的增加 2)。
您基本上可以对 Prometheus 的实现进行逆向工程,并通过乘以 (requested_range - scrape interval)
并除以 requested_range
得到(非常接近)实际增加量,本质上是回溯 Prometheus 所做的外推。
在你的情况下,这意味着
increase(signups_count[4m]) * (240 - 120) / 240
或者,更简洁地说,
increase(signups_count[4m]) / 2
它要求您了解范围的长度和刮擦间隔,但它会给您您想要的:"ones for ones, and twos for twos, most of the time"。有时你会得到 1.01
而不是 1.0
因为刮痕是 119 秒,而不是相隔 120 秒,有时,如果你的评估与刮痕紧密对齐,可能会包括边界上的一些点或不是在数据点计算中,但它仍然是比 2.0
.
更好的答案
Prometheus 中的 increase()
和 rate()
函数可能会 return 由于外推而产生意外结果。参见 this issue for technical details. Prometheus developers are going to fix this issue in the future - see this design doc。
同时尝试 VictoriaMetrics - it addresses the issue in increase()
and rate()
functions, so they return the expected results (e.g. increase(signups_count[4m])
would return the correct integer results). See this article and this comment 了解技术细节。
我发现对于一些图表,我从普罗米修斯那里得到了双精度值,而应该只是一个:
我使用的查询:
increase(signups_count[4m])
抓取间隔设置为
如果我查询实际存储的数据:
curl -gs 'localhost:9090/api/v1/query?query=(signups_count[1h])'
"values":[
[1515721365.194, "579"],
[1515721485.194, "579"],
[1515721605.194, "580"],
[1515721725.194, "580"],
[1515721845.194, "580"],
[1515721965.194, "580"],
[1515722085.194, "580"],
[1515722205.194, "581"],
[1515722325.194, "581"],
[1515722445.194, "581"],
[1515722565.194, "581"]
],
我看到只有两次增加。事实上,如果我查询这些时间,我会看到预期的结果:
curl -gs 'localhost:9090/api/v1/query_range?step=4m&query=increase(signups_count[4m])&start=1515721965.194&end=1515722565.194'
"values": [
[1515721965.194, "0"],
[1515722205.194, "1"],
[1515722445.194, "0"]
],
但是 Grafana(和 GUI 中的 Prometheus)倾向于在查询中设置不同的 step
,对于不熟悉 Prometheus 内部工作原理的人来说,我得到了非常意外的结果。
curl -gs 'localhost:9090/api/v1/query_range?step=15&query=increase(signups_count[4m])&start=1515721965.194&end=1515722565.194'
... skip ...
[1515722190.194, "0"],
[1515722205.194, "1"],
[1515722220.194, "2"],
[1515722235.194, "2"],
... skip ...
知道 increase()
只是
如何避免这种情况?我如何让 Prometheus/Grafana 在大多数情况下显示一个对一个,两个对两个?除了增加刮擦间隔(这将是我最后的手段)。
我了解普罗米修斯 isn't an exact sort of tool,所以如果我不是一直都有一个好号码,但大多数时候都很好,那对我来说很好。
我还缺少什么?
这被称为 aliasing,是信号处理中的一个基本问题。您可以通过提高采样率来稍微改善这一点,4m 范围对于 2m 范围来说有点短。尝试 10 米范围。
这里例如在 1515722220 执行的查询只看到 580@1515722085.194 和 581@1515722205.194 样本。在 2 分钟内增加了 1,在 4 分钟内推断增加了 2 - 这符合预期。
任何基于指标的监控系统都会有类似的工件,如果你想要 100% 的准确性,你需要日志。
increase()
将始终(大约)使您的设置实际增加一倍。
原因是(按照目前的实施):
increase()
是(如您观察到的)rate()
的语法糖,即它是 return 乘以rate()
的值乘以秒数在你指定的范围内。在您的情况下,它是rate() * 240
.rate()
在其计算中使用外推法。在绝大多数情况下,4 分钟的范围将 return 恰好 2 个数据点,几乎恰好相隔 2 分钟。然后将速率计算为最后一个和第一个之间的差异(即您的案例中的 2 点)除以 2 点的时间差(在 99.99% 的案例中约为 120 秒)乘以您请求的范围(恰好 240 秒) ).因此,如果两点之间的增幅为零,则利率为零。如果 2 点之间的增量为1.0
,则计算出的rate()
将接近2.0 / 240
,因此,increase()
将为2.0
。
这种方法在计数器平稳增加时效果很好(例如,如果您每 2 分钟有或多或少固定的注册数量)。但是对于一个很少增加的计数器(就像你的注册计数器一样)或者一个尖锐的计数器(比如 CPU 使用率)你会得到奇怪的高估(比如你看到的增加 2)。
您基本上可以对 Prometheus 的实现进行逆向工程,并通过乘以 (requested_range - scrape interval)
并除以 requested_range
得到(非常接近)实际增加量,本质上是回溯 Prometheus 所做的外推。
在你的情况下,这意味着
increase(signups_count[4m]) * (240 - 120) / 240
或者,更简洁地说,
increase(signups_count[4m]) / 2
它要求您了解范围的长度和刮擦间隔,但它会给您您想要的:"ones for ones, and twos for twos, most of the time"。有时你会得到 1.01
而不是 1.0
因为刮痕是 119 秒,而不是相隔 120 秒,有时,如果你的评估与刮痕紧密对齐,可能会包括边界上的一些点或不是在数据点计算中,但它仍然是比 2.0
.
increase()
和 rate()
函数可能会 return 由于外推而产生意外结果。参见 this issue for technical details. Prometheus developers are going to fix this issue in the future - see this design doc。
同时尝试 VictoriaMetrics - it addresses the issue in increase()
and rate()
functions, so they return the expected results (e.g. increase(signups_count[4m])
would return the correct integer results). See this article and this comment 了解技术细节。