使用 Shell 脚本监控服务器 IOWait 并发送邮件告警

前言

[1. IO Wait 简介](#1. IO Wait 简介)

[2. 获取 IOWait 的方法](#2. 获取 IOWait 的方法)

[3. Shell 脚本实现](#3. Shell 脚本实现)

脚本说明

[4. 常见问题与解决](#4. 常见问题与解决)

[4.1 iowait 取到空值](#4.1 iowait 取到空值)

[4.2 awk 比较浮点数报错](#4.2 awk 比较浮点数报错)

[4.3 多收件人邮件只收到了部分邮箱](#4.3 多收件人邮件只收到了部分邮箱)

[4.4 测试告警](#4.4 测试告警)

[5. 总结](#5. 总结)

前言

在生产环境中,磁盘 IO 瓶颈是影响服务器性能的重要因素之一。本文介绍如何用 Shell 脚本监控 IO Wait,并在超过阈值时通过邮箱告警,同时讨论多收件人和邮件发送中常见的问题及解决方法。


1. IO Wait 简介

  • IOWait 是 CPU 等待磁盘或网络 IO 完成的时间百分比。

  • 当 IOWait 高于阈值时,意味着系统可能出现 IO 瓶颈,需要关注磁盘性能。


2. 获取 IOWait 的方法

我们使用 iostat 命令获取 CPU IO Wait 值:

复制代码
iostat -cy 1 1 | awk '/^ /{print $4}'

说明:

  • -c:显示 CPU 使用情况

  • -y:跳过平均值(可选)

  • 1 1:每隔 1 秒采样一次,只输出一次

  • awk '/^ /{print $4}':匹配数据行,取第 4 列(%iowait)

注意:不能直接用 awk 'END{print $4}',因为最后一行可能是空行或表头,导致取到空值。


3. Shell 脚本实现

下面是一个完整示例,带告警邮件功能:

复制代码
#!/bin/bash

#设置阈值(设置负数用于测试)
IOWAIT_WARNING=-1

#设置邮件收件人
MAIL_TO="3426848201@qq.com,2270993679@qq.com"

#邮件标题
TITLE="服务器IO等待告警"

#iowait获取
iowait=$(iostat -cy 1 1 | awk '/^ /{print $4}')

#获取当前系统时间
TIME=$(date +"%F %T")

#判断iowait是否为空,防止误报
if [ -z "$iowait" ]; then
   echo "iowait值为空"
   exit 0
else
    #判断是否大于阈值,大于则发送邮件告警
    if awk "BEGIN {exit !($iowait > $IOWAIT_WARNING)}"; then
    warning_info="${TIME}
    主机: $(hostname)
    iowait当前值为: ${iowait}%
    已超过阈值: ${IOWAIT_WARNING}%"
   (
      echo "Subject: $TITLE"
      echo "To: $MAIL_TO"
      echo
      echo -e "$warning_info"
   ) | msmtp -t
   else
       echo "iowait值正常" 
   fi
fi

脚本说明

  1. 变量说明

    • IOWAIT_WARNING:告警阈值,可在测试时设置负数强制触发

    • MAIL_TO:收件人,多收件人空格分隔

    • TITLE:邮件标题

  2. 邮件发送

    • msmtp -t 从邮件头读取收件人 To: 和标题 Subject:

    • 如果在 /etc/msmtprc 已配置 from,脚本中无需再写 From:

    • 多收件人时最好用空格或逗号分隔,但不同 SMTP 对空格/逗号解析可能不同,必要时分开发送。


4. 常见问题与解决

4.1 iowait 取到空值

  • 原因:awk 'END{print $4}' 可能取到空行或表头

  • 解决:使用 /^ /{v=$4} END{print v} 或直接 iostat -cy 1 1 | awk '/^ /{print $4}'


4.2 awk 比较浮点数报错

  • 原因:小数点在 Shell 展开时可能导致语法错误

  • 解决:使用 awk -v io="$iowait" -v th="$IOWAIT_WARNING" 传入变量

补充:

  • -v io="$iowait"

    把 shell 变量 $iowait 传给 awk 内部变量 io

  • -v th="$IOWAIT_WARNING"

    把阈值 $IOWAIT_WARNING 传给 awk 内部变量 th

  • 'BEGIN {exit !(io > th)}'

    • BEGIN 块在 awk 开始处理任何输入之前执行

    • io > th 为真时,!(io > th) 为假,exit 0 → awk 返回成功

    • io > th 为假时,!(io > th) 为真,exit 1 → awk 返回失败


4.3 多收件人邮件只收到了部分邮箱

  • 原因:

    1. SMTP 服务器限制,只允许发给同域邮箱

    2. 收件人不存在或拼写错误

    3. 邮件头 To: 与 SMTP 命令行不匹配

  • 解决:

    • 确保邮箱有效

    • 使用 msmtp -t 并在 To: 中列出所有收件人

    • 测试时可先用同域邮箱确保收全


4.4 测试告警

  • 可以将阈值设为负数,或临时把 $iowait 赋值为大于阈值的值,强制触发邮件发送逻辑:

    iowait=99.99

4.5 补充知识

awk 的退出码与 shell 的 if

  • shell 在执行一条命令后,可以通过 $? 取到退出状态

  • if 判断的是真假:退出状态为 0 表示"真"(success),非 0 表示"假"(failure)。

  • awk 程序里执行 exit N,退出码就是 N,shell 能接收到。


awk 里布尔运算

  • 在 awk 中,布尔表达式 ($iowait > $THRESHOLD) 的值是真或假:
    1
    0

  • ! 是逻辑非运算符:
    !1 = 0
    !0 = 1


为什么写 exit !($iowait > $THRESHOLD)

逐步展开:

  • 假设 $iowait > $THRESHOLD → 表达式值 1!1 = 0exit 0

    shell if 看到退出码 0,认为真,进入 then。

  • 假设 $iowait$THRESHOLD → 表达式值 0!0 = 1exit 1

    shell if 看到退出码 1,认为假,跳过 then。

所以这句相当于:

"如果 $iowait 大于 $THRESHOLD,awk 以状态码 0 退出(shell if 真);

否则 awk 以状态码 1 退出(shell if 假)。"


5. 总结

  • 使用 Shell 脚本 + iostat 可以轻松监控服务器 IO Wait

  • 告警邮件可用 msmtpmailx 发送,多收件人需注意 SMTP 限制

  • 浮点比较、空值检查和邮件头书写是脚本稳定性的关键点

相关推荐
Lin_Aries_04214 小时前
在 CentOS 9 上安装 Docker 的完整指南
linux·docker·centos
我是海飞5 小时前
外置flash提示音打包脚本
运维·服务器·音视频·嵌入式
丁满与彭彭5 小时前
嵌入式学习笔记--Linux系统编程阶段--DAY06进程间通信-消息队列
linux·笔记·学习
etcix5 小时前
for my debian 12 mxlinux install the podman
运维·debian·podman
努力努力再努力wz5 小时前
【c++进阶系列】:万字详解AVL树(附源码实现)
java·运维·开发语言·c++·redis
凉、介6 小时前
U-Boot 多 CPU 执行状态引导
java·服务器·前端
jingfeng5146 小时前
应用层自定义协议与序列化
运维·服务器·网络
egoist20236 小时前
[linux仓库]性能加速的隐形引擎:深度解析Linux文件IO中的缓冲区奥秘
linux·运维·开发语言·缓存·缓冲区