bigywater.tech
微服务 · 72

rate() 与 increase():计数器重置的处理

rate() 和 increase() 为什么会给出小数?窗口取多长?irate 和 rate 怎么选?进程重启时 counter 的哪些增量会丢?这篇用 Prometheus 3.15.0 和增长速度已知的 counter 逐项量出来。

2.18 ~ 3.27
真实增量为 3 的稀疏 counter,在不同时刻查询 increase(c[1m]) 得到的范围
0.0 ~ 400.0 vs 80.0 ~ 160.0
同一个 counter 的 irate 与 rate 的取值范围(/s)
300 → 100
重启后新进程增长到 300、而 Prometheus 只看到 200 → 300 时,实际新增与 increase 算出的增量

increase 的外推

实测 · 本机执行输出
  counter  | 60 s 窗口里的真实增量 | 得到结果的时刻数 | increase 最小 | increase 最大 | increase 平均
  ---------+---------------+----------+-------------+-------------+------------
  c_steady | 600           | 17       | 599.97      | 600.03      | 600.00     
  c_sparse | 3             | 17       | 2.18        | 3.27        | 2.95       
  increase() 用窗口内第一个和最后一个样本之间的增量,按窗口边界与样本的距离做线性外推;外推之后整数 counter 也会得到小数,单个窗口的结果会偏离真实值,取平均更接近真实值

increase 对窗口边界外推,整数 counter 会得到小数,稀疏事件偏差更大。

窗口与抓取间隔

实测 · 本机执行输出
  窗口 W | 窗口内的样本数 | rate(c_steady[W])
  -----+---------+------------------
  5 s  | 1       | (没有结果)           
  10 s | 2       | 10.00            
  15 s | 3       | 10.00            
  20 s | 4       | 10.00            
  30 s | 6       | 10.00            
  rate() / increase() 至少要窗口里有两个样本才能算;窗口恰好等于抓取间隔时可能只有一个样本,返回空;窗口里只有两三个样本时结果受外推和抓取时刻的影响很大,所以窗口至少要取抓取间隔的几倍

窗口里至少要有两个样本才能算,窗口要取抓取间隔的几倍。

irate 与 rate

实测 · 本机执行输出
  函数                  | 最小(/s) | 最大(/s) | 标准差   | 取值的时刻数
  --------------------+--------+--------+-------+-------
  irate(c_burst[30s]) | 0.0    | 400.0  | 169.7 | 17    
  rate(c_burst[30s])  | 80.0   | 160.0  | 33.9  | 17    
  整个周期(20 s)里平均每秒 +100。irate 反映抓取到的最近两点之间的瞬时速度,变化剧烈,适合看当前的尖峰;rate 对整个窗口平均,更平滑,适合告警和长期趋势

irate 看最近两个样本的瞬时速度,rate 对整个窗口平均。

重启与丢失

实测 · 本机执行输出
  两个进程实际增加的总量 3600(崩溃前 1200 + 重启后 2400);Prometheus 抓到的第一个样本是 0;崩溃前最后一次成功抓到的值是 1000,崩溃时是 1200,这 200 的增量永远没有被抓到。所以 increase 能反映的上限是 实际总量 − 第一个样本的值 − 没被抓到的增量 = 3600 − 0 − 200 = 3400
  increase(c[2m]) = 3448,与上限 3400 的差是 +48(increase 会对窗口两端做外推,这个差我没有逐项拆解);崩溃前后没被抓到的那 200 个增量无法从 Prometheus 里找回
  样本序列(时间相对第 0 s,值):4s:400 6s:600 8s:800 10s:1000 18s:200 20s:400 22s:600 24s:800 26s:1000 28s:1200 30s:1400 32s:1600 34s:1800 36s:2000 38s:2200 40s:2400

崩溃前后没被抓到的增量无法找回。

认不出的重启

实测 · 本机执行输出
  抓到的样本:-0.1s:200 +1.9s:300 +3.9s:300;重启前最后抓到 200,重启后新进程实际增加 300(0 → 300);Prometheus 看到 200 → 300,没有出现“值变小”,resets() = 0.0。窗口里 200 → 300 这一段的增量是 100,真实新增是 300,少算了 200
ERRORS {}

重启后马上增长到比崩溃前还大的值,Prometheus 看不出是重启。

分步演示

rate 与 increase
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.8 / Go / nginx / Envoy / etcd / Consul / Nacos / OpenTelemetry / Prometheus(按各篇注明用到哪些及版本);所有服务都是本机自己起的进程,端口 9150 以上,只监听 127.0.0.1,不连任何外部服务,不碰本机已有的实例;故障用 kill -9 进程、让连接断开或在代码里注入延迟与错误来制造;计时用 time.perf_counter,数字每次运行会有小幅抖动。Prometheus 3.15.0;被抓取的 counter 是我写的 Python 服务,按设定速度增长(真实增量已知);第一、二、三节同一次运行(抓取间隔 5 s,17 个查询时刻),第四、五节抓取间隔 2 s;每节只跑了一次,数字每次运行略有不同(例如开发中 increase 的结果 3445、3446、3448)
    • 没有验证:Grafana 的 $__rate_interval 与 min_step 的取法;recording rule 里的 rate 在不同 evaluation_interval 下的行为;Prometheus 对 counter 重置的启发式在其他模式下的表现;OpenTelemetry delta 型指标(没有重置问题但依赖导出器);increase 外推公式的具体细节(我没有拆解 +48 的来源)
    京ICP备2026067502号-1京公网安备11010502063487号