服务器突然变得卡顿,SSH登录响应缓慢,业务接口超时告警开始轰炸。很多人的第一反应是CPU爆了或者内存满了,但打开top一看,CPU使用率并不高,内存也还有余量。这时候,罪魁祸首很可能就是磁盘I/O等待。简单说,CPU在等待磁盘读写操作完成,这段时间CPU是空闲的,但进程却卡在那里动不了。在Linux系统中,这个指标通常通过iowait来体现,它表示CPU等待I/O操作完成的时间百分比。Zabbix作为生产环境中广泛使用的监控工具,能不能精准抓到这个问题?答案是肯定的,但默认配置往往不够用,需要我们做一些定制。
iowait到底是什么,为什么需要专门监控iowait不是磁盘速度变慢,而是CPU在等磁盘。比如一个数据库查询需要读取大量数据,磁盘在疯狂寻道和传输,CPU只能干等着。在top命令里,%iowait这一列就是我们要关注的。如果这个值持续超过30%,甚至飙到50%以上,系统响应就会明显变慢。但有个坑需要注意,iowait高不一定代表磁盘有问题,也可能是CPU太闲了。反过来,如果CPU本身负载很高,iowait反而可能显示很低,因为CPU忙着处理其他任务,等待I/O的比例被稀释了。所以这个指标必须结合其他数据一起看,不能孤立判断。
Zabbix默认模板的局限很多人装了Zabbix Agent,挂上Template OS Linux模板,以为就能监控一切。实际上,默认模板对I/O等待的监控非常粗糙。它通常会采集system.cpu.iowait这个键值,但这个值是一个瞬时百分比,可能在你查看的时候刚好不高,问题就被掩盖了。更关键的是,默认模板的触发器阈值通常设得比较保守,或者根本没有针对iowait的触发器。等到你发现业务出问题时,再去查Zabbix历史数据,才发现iowait早就飙过几次了,只是没告警。所以我们需要自己动手,建立一个更精准的I/O等待监控项和触发器。
第一步:确认Zabbix Agent能采集到数据先别急着在界面配置,直接在服务器上测试一下。Zabbix Agent自带一个键值system.cpu.iowait,我们可以用zabbix_get或者直接在Agent端用命令测试。在Agent端执行以下命令可以看到原始数据:
zabbix_agentd -t system.cpu.iowait
正常会返回一个类似system.cpu.iowait [d|0.500000]的值,这个0.5就代表当前iowait百分比。如果这个命令没输出或者报错,检查Agent配置文件里的EnableRemoteCommands是否开启,以及Server配置是否正确。另外要注意,这个值是Zabbix Agent从/proc/stat文件里计算出来的,不是直接读取的。Agent会取两个时间点的差值来计算百分比,所以这个值本身就是一段时间内的平均值,不是瞬时值。
第二步:创建更精准的监控项在Zabbix前端,找到对应主机,进入监控项配置。我们不直接改默认模板,而是创建一个新的监控项,这样升级模板时不会被覆盖。监控项类型选择Zabbix客户端,键值就用system.cpu.iowait,信息类型选浮点数,单位填%,更新间隔建议设成30秒或1分钟。太短了没意义,因为iowait本身波动就大,太长了又可能错过突发问题。历史数据保留时间根据磁盘空间来定,一般7天到30天都行。趋势存储可以设长一点,365天也没问题。
这里有个细节很多人忽略:自定义倍率。iowait的值本身就是百分比,Zabbix Agent返回的也是百分比数值,所以自定义倍率保持1就行,不要画蛇添足乘100。另外,如果你们服务器用的是NVMe SSD或者高端存储,iowait可能常年低于1%,这时候用百分比显示就不太直观,可以考虑在触发器里用绝对值判断,而不是百分比阈值。
第三步:设计靠谱的触发器触发器是告警的核心,也是最容易出问题的地方。如果简单设一个“iowait大于50%就告警”,大概率会被半夜的备份任务刷屏。我们需要的是一个既能抓到持续性问题,又能过滤掉瞬时峰值的触发器。推荐使用avg函数,比如计算最近5分钟的平均iowait,如果超过30%就触发告警。表达式可以这样写:
{主机名:system.cpu.iowait.avg(5m)}>30
这个5分钟窗口很关键。如果设成1分钟,可能某个进程短暂写日志导致的iowait尖峰就会误报。如果设成15分钟,又可能反应太慢。5分钟是一个比较平衡的选择,既能过滤掉大部分瞬时波动,又不会让真正的问题持续太久才被发现。另外建议加一个恢复条件,比如连续两次取值都低于20%才认为恢复,避免告警反复横跳。
更进阶的做法是结合时间段。比如凌晨2点到4点有全量备份,iowait飙高是正常的,这时候告警就是噪音。可以在触发器里加时间条件,或者单独创建一个维护窗口,在备份时段抑制告警。Zabbix的维护周期功能完全可以做到这一点,比在触发器表达式里写复杂的时间判断要简洁得多。
第四步:结合磁盘利用率做关联分析单独看iowait只能知道CPU在等磁盘,但不知道是哪块磁盘在拖后腿。这时候需要把iowait和磁盘利用率关联起来。Zabbix Agent可以采集vfs.dev.read.ops和vfs.dev.write.ops这些键值,能拿到每块磁盘的读写操作数。还有一个更直接的指标是vfs.dev.util,它表示磁盘繁忙程度百分比。如果iowait高,同时某块磁盘的util也接近100%,那基本可以确定是这块盘成为瓶颈了。
配置方法是在同一个主机下,创建磁盘利用率的监控项。键值用vfs.dev.util[sda]这样的格式,sda换成实际的磁盘设备名。然后创建一个聚合图形,把iowait和所有磁盘的util放在同一个时间轴上。当告警触发时,打开这个图形一眼就能看出是哪块盘的问题。这个关联分析在生产环境排障时能节省大量时间,不用再临时敲iostat命令去看。
第五步:利用iostat获取更细粒度的数据system.cpu.iowait只能看到全局的I/O等待,但很多时候我们需要知道是读操作还是写操作导致的等待,以及等待队列有多长。这些数据Zabbix Agent默认不提供,但我们可以通过自定义UserParameter来采集iostat的输出。首先在Agent配置文件里添加:
UserParameter=iostat.await[*],iostat -x $1 1 2 | tail -1 | awk '{print $$10}'
UserParameter=iostat.svctm[*],iostat -x $1 1 2 | tail -1 | awk '{print $$13}'
UserParameter=iostat.avgqu[*],iostat -x $1 1 2 | tail -1 | awk '{print $$9}'
这里$1是磁盘设备名参数,$$10是转义后的awk列号。await是平均等待时间,包含队列等待和实际服务时间,单位是毫秒。svctm是平均服务时间,可以理解为磁盘本身处理请求的速度。avgqu是平均队列长度,这个值如果持续大于1,说明请求开始排队了。这三个指标配合iowait,能非常精准地定位I/O瓶颈到底是磁盘本身慢,还是请求太多排队导致的。
配置完记得重启Agent,然后在Zabbix前端创建对应的监控项,键值分别填iostat.await[sda]、iostat.svctm[sda]、iostat.avgqu[sda],信息类型选浮点数。触发器的设置思路是:await持续高于20ms就要关注,高于50ms基本可以确定磁盘性能有问题。对于SSD,这个阈值要调低很多,通常await超过5ms就算异常了。
第六步:监控特定进程的I/O行为有时候iowait是某个进程疯狂读写导致的,比如日志轮转时压缩大量文件,或者数据库在做checkpoint。如果能监控到具体是哪个进程在大量I/O,排障效率会高很多。Linux的/proc/[pid]/io文件记录了每个进程的读写字节数,我们可以用脚本把这些数据喂给Zabbix。思路是写一个脚本,遍历/proc目录下所有数字目录,读取io文件里的read_bytes和write_bytes,然后计算差值,找出读写量最大的几个进程。
这个脚本可以放在Agent的UserParameter里定时执行,返回JSON格式的数据。Zabbix从4.0版本开始支持依赖项和低级别发现,可以用这个特性动态发现I/O密集型进程。不过这个方案比较复杂,对于大多数场景,前面的磁盘级别监控已经够用了。只有在排查具体应用问题时,才需要深入到进程级别。
第七步:告警后的自动化处理监控发现问题只是第一步,快速响应才是关键。当iowait告警触发时,除了发邮件或短信,还可以配置动作脚本自动收集现场信息。比如自动执行iostat -x 1 5,把输出结果保存到临时文件,或者直接追加到告警消息里。Zabbix的动作功能支持远程命令,可以在告警触发时在目标主机上执行脚本。这个脚本可以收集top的I/O相关进程、iotop的输出、dmesg里最近的磁盘相关错误等。这些信息随着告警一起推送,收到告警的人不用再登录服务器就能初步判断问题严重程度。
另一个实用的自动化是动态调整监控频率。正常情况下iowait监控间隔设60秒就够了,但当iowait超过阈值后,可以通过Zabbix API自动把监控间隔改成10秒,密集采集一段时间的数据,等恢复后再改回正常频率。这样既节省了平时的存储空间,又能在出问题时拿到高分辨率的数据。
常见误区和注意事项有个很常见的误解是iowait高就要换更快的磁盘。实际上,很多iowait问题根本不在磁盘硬件上。比如应用层频繁做fsync强制刷盘,再快的SSD也扛不住每秒几千次fsync。这时候优化应用代码或者调整文件系统挂载参数,效果远比换硬件好。还有虚拟化环境下的iowait,可能和宿主机上的其他虚拟机争抢资源有关,这时候在虚拟机内部看iowait高,但根因在宿主机层面。Zabbix监控到iowait异常后,一定要结合虚拟化平台的监控数据一起分析。
另外,Zabbix Agent采集iowait数据时,本身也会消耗一点CPU和I/O资源。如果监控项设得太多太密,Agent自身就可能成为负担。建议一台主机上的自定义监控项总数控制在200个以内,采集间隔不要低于30秒。对于iowait这种系统级指标,用Agent自带的键值就足够了,不需要额外写脚本去读/proc/stat再算一遍,那样反而增加开销。
构建完整的I/O监控体系把前面这些点串起来,一个完整的I/O监控体系应该包含三个层次。第一层是全局指标,就是system.cpu.iowait,用来快速判断有没有I/O等待问题。第二层是磁盘级指标,包括每块磁盘的util、await、svctm和队列长度,用来定位是哪块盘的问题。第三层是进程级指标,用来找出是哪个应用导致的I/O压力。三层之间通过Zabbix的图形和触发器联动,形成从宏观到微观的排查链路。
这个体系搭建完成后,再遇到服务器卡顿,你的排查路径会非常清晰:先看iowait是否异常,如果是,再看各磁盘的util和await,找到问题磁盘后,最后看是哪个进程在大量读写。整个过程不需要登录服务器敲命令,在Zabbix大屏上就能完成90%的诊断工作。对于运维团队来说,这套监控的价值不在于告警本身,而在于大幅缩短了平均故障定位时间。
