每秒十个请求和每秒一个请求的两组不等流量分别合并错误量与请求量,得到服务加权占比 0.6 除以 11,约百分之五点四五。

记录规则应保留比例的分子和分母

当查询成本和复用频率足以支持预计算时,反复使用的服务级查询适合做成记录规则。关键问题是保存什么。如果只保存每个实例的错误百分比,可能丢掉之后聚合必需的流量规模;同时保存错误速率与请求速率,则保留了分子和分母,消费者能够据此计算按实际请求量加权的服务错误占比,而不是把每台实例当成相同流量。 保留分子与分母,先求速率再聚合,并对齐流量总体、时间窗口和服务标签。数值来自原文本地合成规则实验。历史通过范围保持不变;本轮没有新增测试或性能结论。 百分比必须对应明确的总体 假设繁忙实例每秒处理十个请求,每秒发生零点一个错误;空闲实例每秒处理一个请求,却每秒发生零点五个错误。两个实例的错误占比分别为百分之一与百分之五十。直接平均得到百分之二十五点五,相当于给两个实例相同权重,但它们的请求量实际上相差十倍。这个数描述平均实例百分比,不描述服务处理的全部请求。 服务合计每秒处理十一个请求,发生零点六个错误,因此错误占比是 0.6/11,约百分之五点四五。这是聚合错误量除以聚合请求量。两侧必须描述同一组符合条件的流量,并使用相同时间窗口。如果分子排除了分母包含的一类失败,或者两侧聚合了不同服务,面板即使计算得很快,结果也仍然不成立。 按顺序建立规则依赖 先对每条计数器序列应用 rate,使已经观测到的重置能够在聚合前得到处理,再按照消费者确实需要的维度求和。本例依次记录服务与实例维度的请求速率、服务请求速率、服务错误速率,以及最终服务错误占比。第一个实例级中间结果用于展示明确的前后依赖,后续规则实际消费这个结果,而不是重复写一个看似相关的名字。 四条规则位于同一个组,按声明顺序运行,使用相同评估时间。分子与分母都保留匹配的 service 标签,因此除法能够把对应服务配对。如果分母额外保留实例标签,就会改变向量匹配关系,可能导致没有结果,或需要重新设计连接方式。测试应同时检查输出标签和数值,不能只看到一个合理百分比就认为查询正确。 命名应说明聚合层级和范围。两分钟速率与三十分钟速率即使当前值恰好相同,也不是同一种量。应在规则旁记录哪些事件计入总体,并明确消费它的面板与告警。沿用旧名称但修改公式,只会改变未来记录样本,不会重新解释已经写入的历史。需要保持时间可比性时,定义变更必须被消费者看见。 坏掉的样子 平均百分比可能让一台低流量故障实例主导整个服务报告,也可能掩盖高流量实例的失败。提高评估频率不会修复这个算术问题,应恢复底层计数或速率,在分别聚合后再相除。如果最后只保留了百分比,通常无法仅靠这些百分比重建原始流量权重,因为相同占比可以来自完全不同的请求数量。 零流量是另一类情况。分母为零时,错误占比并没有被定义为零;分子缺失也可能代表仪表化缺少序列,而不是没有错误。应根据指标契约明确这些语义,避免自动把所有空结果或未定义数值显示成健康的零。还应确认健康期间错误计数器是否持续导出,避免只有发生错误后才创建序列,导致正常状态与数据缺失难以区分。 快速验证 保存为 recording-weighted.py,在 PATH 中准备已安装的 promtool,或用 PROMTOOL 指定可执行文件,再运行 python3 recording-weighted.py。保留的 2026-10-15 审核记录说明,完整程序在 promtool 3.14.0 与 Python 3.12.14 上通过;本次源码审核没有重跑规则引擎。真实规则引擎评估每分钟一份的合成计数器,包含权重明显不同的实例,以及独立的零流量、序列缺失案例。 from pathlib import Path from tempfile import TemporaryDirectory import os import shutil import subprocess promtool = shutil.which(os.environ.get("PROMTOOL", "promtool")) if promtool is None: raise SystemExit("Set PROMTOOL to an installed promtool executable") promtool = str(Path(promtool).resolve()) tests = r"""evaluation_interval: 1m rule_files: - rules.yml tests: - interval: 1m input_series: - series: "http_requests_total{service=\"checkout\",instance=\"busy\"}" values: "0+600x5" - series: "http_errors_total{service=\"checkout\",instance=\"busy\"}" values: "0+6x5" - series: "http_requests_total{service=\"checkout\",instance=\"quiet\"}" values: "0+60x5" - series: "http_errors_total{service=\"checkout\",instance=\"quiet\"}" values: "0+30x5" promql_expr_test: - expr: "service:http_requests:rate2m" eval_time: 5m exp_samples: - labels: "{__name__=\"service:http_requests:rate2m\",service=\"checkout\"}" value: 11 - expr: "abs(service:http_errors:rate2m - 0.6) < bool 1e-12" eval_time: 5m exp_samples: - labels: "{service=\"checkout\"}" value: 1 - expr: "abs(service:http_errors:ratio_rate2m - 0.6/11) < bool 1e-12" eval_time: 5m exp_samples: - labels: "{service=\"checkout\"}" value: 1 - expr: "abs(avg(rate(http_errors_total[2m]) / rate(http_requests_total[2m])) - 0.255) < bool 1e-12" eval_time: 5m exp_samples: - labels: "{}" value: 1 - interval: 1m input_series: - series: 'http_requests_total{service="idle",instance="one"}' values: "0+0x5" - series: 'http_errors_total{service="idle",instance="one"}' values: "0+0x5" promql_expr_test: - expr: 'count(service:http_errors:ratio_rate2m != service:http_errors:ratio_rate2m)' eval_time: 5m exp_samples: - labels: "{}" value: 1 - interval: 1m input_series: [] promql_expr_test: - expr: 'count(service:http_errors:ratio_rate2m) or vector(0)' eval_time: 5m exp_samples: - labels: "{}" value: 0 """ rules = r"""groups: - name: service-rates interval: 1m rules: - record: instance:http_requests:rate2m expr: sum by (service, instance) (rate(http_requests_total[2m])) - record: service:http_requests:rate2m expr: sum by (service) (instance:http_requests:rate2m) - record: service:http_errors:rate2m expr: sum by (service) (rate(http_errors_total[2m])) - record: service:http_errors:ratio_rate2m expr: service:http_errors:rate2m / service:http_requests:rate2m """ with TemporaryDirectory(prefix="prom-rule-test-") as directory: work = Path(directory) (work / "tests.yml").write_text(tests, encoding="utf-8") (work / "rules.yml").write_text(rules, encoding="utf-8") subprocess.run([promtool, "test", "rules", "tests.yml"], cwd=work, check=True, timeout=45) 预期输出为 SUCCESS。记录请求速率为十一,错误速率为零点六,最终占比为 0.6/11。另外一项断言明确展示,错误的实例比例平均法得到 0.255。涉及浮点除法的比较使用很小的数值容差,标签断言则确认仍保留 checkout 服务身份。这些检查同时覆盖计算次序、依赖输出和最终聚合口径。 ...

八月 31, 2027 · 2 分钟 · XB Field Notes