Zabbix的告警能力建立在触发器之上,而触发器的灵魂就是表达式。一条写得好的表达式,既不会漏报关键故障,也不会因为一次抖动就疯狂发通知。本文从表达式的基本结构入手,结合实际监控场景,把常用函数和编写技巧讲透。

触发器表达式的基本结构
一条完整的触发器表达式由监控项引用、函数、参数和比较运算符组成。最简单的形式是“函数(监控项键值) 运算符 阈值”。以CPU负载为例,表达式可以写成{host:system.cpu.load.avg(1m)}>2,含义是取该主机最近1分钟CPU负载的平均值,大于2就进入PROBLEM状态。
花括号内部的第一部分是主机名或模板名,冒号后面是监控项的键值(key),再往后是函数名和参数。需要注意版本差异:Zabbix 5.4之前使用{host:key.func(params)}的写法,函数放在键值之后;5.4及以后推荐使用新语法func(/host/key,params),函数放在最前面。两种写法在旧版本系统中都可能遇到,读别人配置时要能分辨。
比较运算符除了常见的>、<、=、#(不等于)之外,还有几个容易忽略的:>=、<=,以及专门用于字符串匹配的正则表达式符号=~和!~。触发器的严重性级别和表达式本身无关,需要在触发器属性里单独设置。
常用监控函数详解
last是最常用的函数,表示取最新的值。比如last(/host/vfs.fs.size[/,pused])>90表示根分区使用率最新值超过90%。last支持偏移参数,last(/host/key,#2)取倒数第二个值,这在判断“连续两次都超阈值”时很有用。
avg、min、max属于统计类函数,参数是时间窗口。avg(/host/system.cpu.util,5m)>80表示最近5分钟CPU平均使用率高于80%。用平均值而不是瞬时值做判断,可以有效过滤掉短暂的毛刺,这是生产环境里最推荐的做法。反过来,min适合判断“一直都很高”的情况,max适合捕捉峰值。
nodata用于检测Agent失联,表达式nodata(/host/agent.ping,3m)=1表示3分钟内没有收到任何数据。注意nodata的判断依赖Proxy或Server的可达性,如果Zabbix Server本身和网络抖动,可能出现误报,建议配合监控项的“类型”设置一起使用。diff函数检测值是否发生变化,常用于监控配置文件是否被改动。count可以统计时间窗口内满足条件的次数,比如count(/host/system.cpu.util,10m,"gt","80")>8表示10分钟内有超过8次采集值高于80。
多条件组合与优先级
真实场景往往需要多个条件叠加。比如“磁盘使用率超过90% 并且 持续了10分钟”,可以利用触发器本身的“事件持续多个周期生成”机制,也可以直接在表达式里组合:min(/host/vfs.fs.size[/data,pused],10m)>90。如果要用逻辑运算符,and要求两边都成立,or只要一边成立即可,not取反。
优先级方面,not的优先级最高,其次是and,最后是or。表达式A or B and C实际被解析为A or (B and C),如果本意是“(A或B)并且C”,必须手动加括号写成(A or B) and C。这是个非常经典的坑,出问题时先检查括号。
Zabbix还支持两个独立的表达式分支:Problem expression和OK event expression。默认情况下恢复条件是问题条件不成立,但有时需要不对称的判断,比如进入故障要求CPU高于90%,恢复则要求低于70%,中间留出缓冲带,避免在阈值附近反复震荡产生告警风暴。
典型场景表达式示例
下面给出几个可以直接套用的模板,替换主机名和键值即可使用。首先是内存不足,判断可用内存低于总量的10%:
last(/host/vm.memory.size[available]) < last(/host/vm.memory.size[total]) * 0.1
其次是检测服务端口是否挂掉,配合net.tcp.service监控项:
last(/host/net.tcp.service[tcp,,80]) = 0
再看一个组合场景:磁盘空间告警但排除临时扩容窗口,通过forecast预测磁盘是否会在24小时内写满:
forecast(/host/vfs.fs.size[/data,pfree],1h,24h) < 0
这个表达式的意思是根据最近1小时的增长趋势,预测24小时后剩余空间是否归零,相比固定阈值告警能提前很多发现问题。timeleft函数与它类似,直接返回预计到达某个值还剩多少时间。
编写时的常见坑与建议
第一个坑是直接用瞬时值做阈值判断。CPU偶尔冲到100%再正常不过,如果写成last(...)>90就会频繁误报,改用avg(...,5m)会安静很多。第二个坑是忘记处理单位,Web界面里看到的值可能带单位显示,但表达式运算用的是原始数值,比如网卡流量监控项如果是bps,写阈值时要做换算。
第三个坑是时间窗口设置过短。窗口太短对采集间隔敏感,如果采集间隔是5分钟,那么avg(...,1m)实际上和last没有区别。建议时间窗口至少是采集间隔的3倍以上。第四个坑是模板继承时覆盖了表达式,修改前先确认触发器是定义在本模板还是父模板上,否则改了不生效还找不到原因。
最后建议把表达式写得可读性强一些,虽然一行塞下五六个条件技术上可行,但维护起来非常痛苦。可以适当拆分成多个触发器,分别对应不同的严重性级别,比如磁盘使用率85%时发警告、95%时发严重告警,这样值班人员一眼就能判断紧急程度。写完表达式后,善用Web界面里的“测试”功能,输入历史数据模拟运算结果,上线前就能验证逻辑是否正确。