4. PromQL 算术与比较运算符:在告警表达式中的精准应用
算术运算符与比较运算符是 PromQL 告警表达式的核心构建块。算术运算符将原始指标转换为有意义的业务比率或增量,而比较运算符则将这些计算结果与预设阈值进行判定,最终触发告警。理解这两类运算符的语义、优先级及在告警场景下的特殊行为,是编写精准告警表达式的基础。
4.1 算术运算符:从原始指标到业务语义
PromQL 支持五种标准算术运算符,它们作用于瞬时向量或标量,生成新的瞬时向量。在告警表达式中,算术运算符主要用于将原始指标转换为更具可读性和业务意义的比率、百分比或增量。
| 运算符 | 名称 | 告警场景典型用法 | 示例 |
|---|---|---|---|
+ |
加法 | 合并多个来源的相同维度指标 | node_memory_MemFree_bytes + node_memory_Cached_bytes |
- |
减法 | 计算剩余容量或差值 | node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes |
* |
乘法 | 单位换算或权重调整 | rate(http_requests_total[5m]) * 1000 |
/ |
除法 | 计算比率、利用率、错误率 | rate(http_requests_total{status="5xx"}[5m]) / rate(http_requests_total[5m]) |
% |
取模 | 周期性检测、轮询调度余量 | time() % 3600 |
/ 运算符是最常用的算术运算符,因为它能将数值(如请求数、错误数)转化为比率,消除实例规模差异,使阈值在不同规模的服务实例间保持一致。
4.2 比较运算符:触发告警的判定逻辑
比较运算符将算术运算后的结果与阈值进行比较,产生布尔结果。在 PromQL 告警规则中,比较运算符是触发告警的直接条件。PromQL 支持六种比较运算符:==、!=、>、<、>=、<=。
比较运算符在告警表达式中有两种行为模式:
- 过滤模式(默认): 保留满足条件的样本,丢弃不满足的样本。如果结果为空,则不触发告警。
- 布尔模式(使用
bool修饰符): 返回 0 或 1,始终保留所有时间序列。在告警规则中通常不使用bool模式,因为告警引擎需要明确的触发/不触发语义。
== 比较浮点数时,由于精度问题,可能导致告警抖动。建议对浮点指标使用范围比较(如 >= 和 <= 组合),或对整数指标使用 ==。
4.3 运算符优先级与括号控制
PromQL 运算符遵循明确的优先级规则。在编写复杂告警表达式时,必须理解优先级以避免逻辑错误。
| 优先级 | 运算符 | 结合性 |
|---|---|---|
| 1(最高) | ^ |
右结合 |
| 2 | *、/、% |
左结合 |
| 3 | +、- |
左结合 |
| 4(最低) | ==、!=、>、<、>=、<= |
左结合 |
由于比较运算符优先级最低,算术运算会先执行。这意味着表达式 rate(errors[5m]) / rate(requests[5m]) > 0.05 会先计算错误率,再与 0.05 比较,符合直觉。但复杂场景下仍需使用括号明确分组。
# 正确:先计算比率,再比较
rate(http_requests_total{status="5xx"}[5m]) / rate(http_requests_total[5m]) > 0.05
# 等价但更清晰:使用括号明确分组
(rate(http_requests_total{status="5xx"}[5m]) / rate(http_requests_total[5m])) > 0.05
# 错误意图:想比较两个速率,但实际先计算了除法
rate(http_requests_total{status="5xx"}[5m]) > 0.05 / rate(http_requests_total[5m]) # 语义错误
4.4 向量匹配:算术运算的维度对齐
当算术运算符作用于两个瞬时向量时,PromQL 会通过标签匹配机制将左侧和右侧的样本配对。理解向量匹配是避免告警表达式产生意外结果的关键。
4.5 告警表达式实战:从算术到比较的完整链路
以下是一个完整的告警表达式编写流程,展示算术运算符与比较运算符如何协同工作:
- 原始指标采集:
http_requests_total{status="5xx"}和http_requests_total - 速率计算:
rate(http_requests_total{status="5xx"}[5m])和rate(http_requests_total[5m]) - 算术运算(除法):
rate(http_requests_total{status="5xx"}[5m]) / rate(http_requests_total[5m])得到错误率 - 比较运算:
... > 0.05判断错误率是否超过 5% - 完整告警规则:
groups:
- name: http_errors
rules:
- alert: HighErrorRate
expr: |
(rate(http_requests_total{status=~"5.."}[5m])
/
rate(http_requests_total[5m])) > 0.05
for: 3m
labels:
severity: critical
annotations:
summary: "HTTP 5xx 错误率超过 5%"
description: "当前错误率 {{ $value | humanizePercentage }}"
4.6 运算符组合的常见模式与反模式
| 模式 | 表达式 | 说明 | 评价 |
|---|---|---|---|
| 错误率告警 | rate(5xx[5m]) / rate(total[5m]) > 0.05 |
使用除法计算比率,阈值与实例规模无关 | 推荐 |
| 饱和度告警 | (used / total) * 100 > 90 |
使用乘法和除法计算百分比 | 推荐 |
| 值告警 | rate(errors[5m]) > 100 |
直接比较原始速率,未归一化 | 反模式:阈值依赖实例流量 |
| 浮点相等 | cpu_usage == 0.5 |
精确比较浮点数 | 反模式:精度问题导致漏告警 |
| 取模周期 | time() % 86400 < 300 |
每天前 5 分钟触发 | 谨慎使用:用于定时检测 |
4.7 运算符与告警降噪的关联
算术运算符的选择直接影响告警的噪声水平。使用除法将指标归一化为比率,可以显著降低因流量波动导致的误告警。例如,一个每秒处理 1000 请求的服务,5xx 错误数从 10 上升到 50,值增加了 5 倍,但错误率仅从 1% 上升到 5%。如果使用值阈值(如 > 30),在低流量时段可能漏报,在高流量时段可能误报。而比率阈值(如 > 5%)在所有流量水平下都保持一致的告警灵敏度。
/ 运算符将指标归一化为比率或百分比。比率阈值在不同规模、不同时段的服务实例间保持语义一致,是告警降噪最有效的单一手段。