4. PromQL 二元运算符:算术、比较与逻辑/集合

在 PromQL 中,二元运算符用于连接两个即时向量或标量,生成新的结果。理解这三类运算符的优先级、匹配机制与使用场景,是编写正确告警表达式的基础。本章按运算符类型逐一拆解,并重点说明向量匹配规则。

4.1 运算符分类总览

类别 运算符 作用 典型告警场景
算术运算符 + - * / % ^ 数值计算 计算 CPU 空闲率、内存使用率、错误占比
比较运算符 == != > < >= <= 条件过滤,返回 0 或 1 阈值告警触发条件
逻辑/集合运算符 and or unless 集合交、并、差 多条件组合告警、排除特定实例
优先级规则: 算术 > 比较 > 逻辑。同一优先级内从左到右结合。建议使用括号 () 显式控制计算顺序,避免歧义。

4.2 算术运算符:向量与标量的计算

算术运算符支持 标量-标量、向量-标量 和 向量-向量 三种组合。在告警表达式中,最常用的是向量-标量运算(如计算百分比)和向量-向量运算(如计算两个指标的比例)。

# 向量-标量:计算 CPU 使用率(百分比)
100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)

# 向量-向量:计算请求错误率
rate(http_requests_total{status=~"5.."}[5m])
/
rate(http_requests_total[5m])
关键点: 向量-向量运算时,PromQL 默认使用 一对一匹配,要求左右两侧向量具有完全相同的标签集合。如果标签不一致,需要使用 on / ignoring 关键字调整匹配规则。

4.3 比较运算符:告警触发条件

比较运算符在 PromQL 中返回 布尔值(0 或 1)。当用于 即时向量 时,它会过滤掉不满足条件的样本,只保留结果为 1 的序列。这是告警规则中 expr 字段的核心机制。

# 触发条件:CPU 使用率超过 90%
(100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)) > 90

# 触发条件:内存可用量低于 512MB
node_memory_MemAvailable_bytes / 1024 / 1024 < 512

比较运算符支持 bool 修饰符,强制返回 0 或 1 而不过滤样本,适用于需要保留所有序列但标记状态的场景。

# 使用 bool 修饰符:所有实例都返回 0 或 1,不丢弃任何序列
http_requests_total > bool 1000

4.4 逻辑/集合运算符:多条件组合

逻辑运算符作用于 即时向量,基于标签集合进行集合运算。在告警表达式中,常用于组合多个条件或排除特定实例。

运算符 含义 告警场景示例
and 交集:结果包含同时出现在左右两侧的序列 CPU 高 且 内存高
or 并集:结果包含出现在左侧或右侧的序列 磁盘使用率高 或 inode 使用率高
unless 差集:结果包含在左侧但不在右侧的序列 所有实例 排除 特定维护实例
# and 示例:CPU 高且内存高
(avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) < 0.1)
and
(node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes < 0.2)

# unless 示例:排除实例 "web-01" 的告警
node_load1 > 5 unless on(instance) node_load1{instance="web-01"}
常见陷阱: 逻辑运算符不进行数值计算,只做集合操作。例如 up == 0 and up{job="api"} 不会返回数值 0,而是返回标签匹配的序列。确保左右两侧的标签集合一致,否则结果可能为空。

4.5 向量匹配机制:一对一、多对一与 group 修饰符

当二元运算符连接两个向量时,PromQL 需要确定如何匹配标签。理解匹配机制是避免告警表达式返回空结果的关键。

向量匹配机制对比 一对一匹配(默认) 左右标签集合必须完全相同 使用 on() 指定匹配标签 使用 ignoring() 忽略标签 多对一匹配 左侧多个序列匹配右侧一个序列 必须使用 group_left 常用于计算分组占比 一对多匹配 右侧多个序列匹配左侧一个序列 必须使用 group_right 较少使用,注意数据膨胀 典型示例:计算每个实例的错误率(多对一匹配) # 左侧:每个实例的 5xx 错误数(按 instance 分组) rate(http_requests_total{status=~"5.."}[5m]) # 右侧:所有实例的总请求数(无 instance 标签) sum by(instance) (rate(http_requests_total[5m])) # 使用 group_left 保留左侧所有 instance 标签 rate(http_requests_total{status=~"5.."}[5m]) / on(instance) group_left sum by(instance) (rate(http_requests_total[5m]))
匹配规则速记:
  • 默认一对一: 左右标签完全一致,无需额外关键字。
  • on(标签列表): 只使用指定标签进行匹配,忽略其他标签。
  • ignoring(标签列表): 忽略指定标签,使用其余标签匹配。
  • group_left / group_right: 多对一或一对多匹配时使用,左侧/右侧保留所有标签。

4.6 运算符优先级与括号使用

PromQL 运算符优先级从高到低为:^ > * / % > + - > == != > < >= <= > and or unless。同一优先级内从左到右结合。

# 不加括号的潜在问题:比较运算符优先级低于算术
# 期望:CPU 使用率 > 90%
# 实际:先计算 100 - avg(...) * 100,再与 90 比较
100 - avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100 > 90

# 正确写法:使用括号明确计算顺序
(100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)) > 90
告警表达式复核要点: 在复核告警规则时,务必检查二元运算符的优先级是否与业务逻辑一致。常见错误包括:忘记括号导致比较条件提前计算、向量匹配标签不一致导致结果为空、逻辑运算符误用为数值计算。建议在 Prometheus 的 Graph 页面中先用 query_range 验证表达式结果,再写入告警规则。