请求计数器回答进程累计记录了多少事件,速率则回答这些事件到来得有多快。Prometheus 的 rate 估计指定范围内每秒平均增长量,修正能够观测到的计数器重置,并向范围边界进行外推。结果具有明确的时间单位,适合观察负载变化;但它不是两次抓取之间全部事件的精确还原,更不能凭空补回没有采到的重启历史。
采样决定能够推断多少事实
普通计数器在重置前持续增长,进程重启是常见的重置原因。相邻已观测样本出现下降时,计数器函数会按重置处理。不过,如果两次抓取之间已经重启并重新累计,而且新值超过旧样本,重置可能完全不可见。提高抓取频率可以提升观测分辨率,但任何查询都不能确定地恢复一段没有被记录的历史。
应先对每条计数器序列求 rate,然后聚合结果。如果先求和,一台实例的增长可能掩盖另一台实例的重置。标签决定序列身份,替换实例使用新标签时,是开始另一条序列,不是自动接续旧实例。队列长度等仪表值本来就允许正常下降,把它们交给计数器速率函数,会把真实下降错误解释为重置。
选择的范围也是指标含义的一部分
范围选择器左开右闭。在第五分钟求 [5m] 时,恰好位于第零分钟的样本不在范围内。对普通浮点计数器求速率至少需要两个可用样本;只有一个样本时得到空结果,并不表示业务流量为零。因此,范围不仅要覆盖正常抓取周期,还需要考虑偶发漏抓后的样本数量,不能仅凭希望曲线更灵敏就无限缩短。
较长窗口通常会平滑短促突发,也让突发离开平均值的时间更晚;较短窗口响应更快,但观测更少,而且可能变成空结果。应依据事件持续时间与检测目标选择范围,并在面板上明确标注。irate 使用最后两个样本,rate 使用所选范围,两者可以针对同一指标回答不同问题,只要面板清楚说明各自含义,不把数值当成同一种口径比较。
规则评估周期决定何时提出查询问题,不决定目标已经被抓取了多少次。如果目标每分钟才采集一次,即使面板每秒刷新,也不会凭空产生新的观测。分析告警响应速度时,需要分别检查采集与评估这两个周期,不能只缩短页面刷新时间。
坏掉的样子
刚创建的序列可能要等第二个样本到来后才出现在速率面板。把所有空值都补成零,可能掩盖采集故障。遇到空白,应先检查原始序列、时间戳和抓取状态,再判断业务是否空闲。另一种问题是窗口太长:短时间过载已经影响用户,但平均线被长窗口稀释,看起来始终平稳,告警因而没有达到阈值。
重置修正不代表缺口对准确性没有影响。漏抓可能隐藏突发或多次重启,范围边界的外推本身也属于估计。increase 以事件数量单位表达相应的范围估计,即使原始计数器只有整数,也可能返回小数。如果场景需要精确账务或计费总数,应依靠业务记账记录,不能把监控面板描述成可以完整重建交易流水的工具。
快速验证
保存为 rate.py,运行 python3 rate.py。环境需要已经安装的 promtool,可以从 PATH 找到,或用 PROMTOOL 指定其可执行文件路径。本轮使用 Python 3.12.14 与 promtool 3.14.0。真实查询引擎在临时目录中评估合成样本,不启动服务器、监听端口或容器,也不联系外部服务。
from pathlib import Path
from tempfile import TemporaryDirectory
import os
import shutil
import subprocess
# Uses a real, installed promtool; no server or Docker runtime is started.
promtool = shutil.which(os.environ.get("PROMTOOL", "promtool"))
if not promtool:
raise SystemExit("Set PROMTOOL to an installed promtool executable")
tests = r"""evaluation_interval: 1m
tests:
- interval: 1m
input_series:
- series: "demo_requests_total{instance=\"steady\"}"
values: "0+60x5"
- series: "demo_requests_total{instance=\"restart\"}"
values: "100 160 220 20 80 140"
- series: "demo_requests_total{instance=\"gaps\"}"
values: "0 60 _ 180 _ 300"
- series: "demo_requests_total{instance=\"one\"}"
values: "_ _ _ _ _ 7"
- series: "combined_requests_total"
values: "100 220 340 200 320 440"
promql_expr_test:
- expr: "rate(demo_requests_total{instance=\"steady\"}[5m])"
eval_time: 5m
exp_samples:
- labels: "{instance=\"steady\"}"
value: 1
- expr: "abs(rate(demo_requests_total{instance=\"restart\"}[5m]) - 5/6) < bool 1e-12"
eval_time: 5m
exp_samples:
- labels: "{instance=\"restart\"}"
value: 1
- expr: "increase(demo_requests_total{instance=\"restart\"}[5m])"
eval_time: 5m
exp_samples:
- labels: "{instance=\"restart\"}"
value: 250
- expr: "irate(demo_requests_total{instance=\"restart\"}[5m])"
eval_time: 5m
exp_samples:
- labels: "{instance=\"restart\"}"
value: 1
- expr: "rate(demo_requests_total{instance=\"gaps\"}[5m])"
eval_time: 5m
exp_samples:
- labels: "{instance=\"gaps\"}"
value: 1
- expr: "rate(demo_requests_total{instance=\"one\"}[5m])"
eval_time: 5m
exp_samples: []
- expr: 'abs(sum(rate(demo_requests_total{instance=~"steady|restart"}[5m])) - 11/6) < bool 1e-12'
eval_time: 5m
exp_samples:
- labels: '{}'
value: 1
- expr: 'abs(rate(combined_requests_total[5m]) - 7/3) < bool 1e-12'
eval_time: 5m
exp_samples:
- labels: '{}'
value: 1
"""
rules = r""""""
with TemporaryDirectory(prefix="prometheus-query-check-") as directory:
root = Path(directory)
(root / "tests.yml").write_text(tests, encoding="utf-8")
if rules:
(root / "rules.yml").write_text(rules, encoding="utf-8")
result = subprocess.run([promtool, "test", "rules", "tests.yml"],
cwd=root, text=True, capture_output=True, timeout=45)
print(result.stdout, end="")
if result.returncode:
print(result.stderr, end="")
raise SystemExit(result.returncode)
断言全部通过时输出 SUCCESS。稳定序列每秒增加一个请求。对于 100 160 220 20 80 140,五分钟 rate 为 5/6,increase 为二百五十,irate 为一。这些结果不同,是因为范围排除了最初样本,随后修正可见重置,再把所得到的平均增长外推到请求时长;二百五十不能被描述为原始样本直接观测到的增量。
带缺口的序列被故意设计为线性增长,因此仍得到每秒一,这个受控结果不能证明任意缺口都无害。只有一个样本的序列则返回空向量。测试分别验证数值与缺失状态,对循环小数使用数值容差。在将规则用于真实服务前,还应补充符合该服务特点的重启、稀疏流量和缺失数据案例,检查告警是否仍表达预期含义。
最后两项检查直接暴露聚合错误:稳定实例和重启实例分别求速率再合并,得到每秒 11/6;预先相加的样本流却得到 7/3,因为重置修正作用于已经混合的数据。两个计算都能成功执行,所以语法正确不证明计数器身份得以保留。程序明确给出混合前后数列与预期值,避免只靠口号说明先求速率的重要性。
来源
- Prometheus: query functions,速率、增量、瞬时速率与重置修正,已核验 2026-10-15。
- Prometheus: querying basics,范围边界与样本选择,已核验 2026-10-15。
- Prometheus: unit testing rules,合成样本与表达式断言,已核验 2026-10-15。