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

发布于:2025-09-07 ⋅ 阅读:(14) ⋅ 点赞:(0)

前言

1. IO Wait 简介

2. 获取 IOWait 的方法

3. Shell 脚本实现

脚本说明

4. 常见问题与解决

4.1 iowait 取到空值

4.2 awk 比较浮点数报错

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

4.4 测试告警

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 限制

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


网站公告

今日签到

点亮在社区的每一天
去签到