需求
数据输入为 counter 类型的指标 demo_tasks__count
实现方式:increase(...) 函数计算某个时段的增量,如 increase(demo_tasks__count[5m]) 计算 5min 内的增量,且会处理 counter 置零的场景
问题
increase() 函数计算结果经常为小数,且与实际该时段内的任务增量不同
初步调研
Prometheus 做 rate 计算时会进行外推 extrapolation,导致出现小数
见讨论:
- https://stackoverflow.com/questions/38665904/why-does-increase-return-a-value-of-1-33-in-prometheus
- https://groups.google.com/g/prometheus-users/c/_aK7im7elUs
- https://groups.google.com/g/prometheus-users/c/qmutsg1c55g
Prometheus 官方专门写了一篇 blog 解释 rate 的计算过程,值得仔细阅读:Blog - How Exactly Does PromQL Calculate Rates?
Take-away
- Prometheus 进行 rate 计算时会进行外推 extrapolation,产生小数
- Prometheus PromQL 当前不适合进行整数类的数据统计,如一段时间的请求数、任务数,Victoria Metrics 可以
尝试解决方案
从邮件组讨论中得到一个神秘公式 https://groups.google.com/g/prometheus-users/c/DhoigmwGx5Q/m/5s3My1EzBAAJ
increase(metric[5m + scrape_interval]) * 5m / (5m + scrape_interval)
套用在现有的数据里测试,发现可以工作!
为什么该公式可以工作
increase(metric[5m + scrape_interval]) * 5m / (5m + scrape_interval)
-
先看 Prometheus 的 rate 计算过程 Blog - How Exactly Does PromQL Calculate Rates?
为了得到区间内的数值增量,一个简单的想法是
increase(metric[5m]) / 5m * (5m - scrape_interval) -
但
increase(metric[5m]) / 5m * (5m - scrape_interval)有致命性问题,也是 Prometheus 试图通过外推去弥补的:丢失区间中的差值
-
我们需要算出来的是当前区间及之前的 1 个 datapoint 的差值!这也正是 Victoria Metrics increase 的实现方案
通过加上 1 个 scape_interval
metric[5m + scrape_interval],可以涵盖区间前一个点,于是产生了公式increase(metric[5m + scrape_interval]) * 5m / (5m + scrape_interval)
5m 指 step interval -
还有遗漏的地方吗?extrapolation 的两类特殊情况,这两种情况是否影响该公式的准确性?
- 指标在 time window 内开始或结束:the extrapolation only extends half an average sample interval toward the window boundary
- 负值不会外推:extrapolation only happens until the expected
0 value is hit
扩展阅读
- 为什么 Victoria Metrics 的 increase 可以得到整数 VictoriaMetrics: PromQL compliance - Roman Khavronenko - Medium
- Design doc: Prometheus x-rate - Extended rate(), increase() and delta()