脚本如何监控磁盘IO读写状态

wen 实用脚本 27

本文目录导读:

脚本如何监控磁盘IO读写状态

  1. 使用 iostat 命令
  2. 使用 iotop 命令
  3. 使用 /proc/diskstats
  4. 综合监控脚本
  5. 告警通知脚本
  6. 使用 dstat 命令
  7. Grafana + Prometheus 方案
  8. 监控要点

我来介绍几种监控磁盘IO读写状态的脚本方法:

使用 iostat 命令

基础监控脚本

#!/bin/bash
# 磁盘IO监控脚本 - iostat方式
# 安装sysstat包(如果未安装)
# apt-get install sysstat  # Debian/Ubuntu
# yum install sysstat      # CentOS/RHEL
# 监控磁盘IO(每2秒刷新)
iostat -x 2
# 查看特定磁盘
iostat -x sda 2
# 监控并输出到文件
iostat -x -t 1 > /var/log/disk_io.log &

高级监控脚本

#!/bin/bash
# 配置
DISK="sda"           # 要监控的磁盘
INTERVAL=1           # 采样间隔(秒)
THRESHOLD_READ=100   # 读IOPS阈值
THRESHOLD_WRITE=100  # 写IOPS阈值
THRESHOLD_UTIL=80    # 磁盘使用率阈值(%)
monitor_disk_io() {
    while true; do
        # 获取IO统计数据
        IO_INFO=$(iostat -x $DISK 1 2 | tail -1)
        # 提取关键指标
        R_IOPS=$(echo $IO_INFO | awk '{print $4}')
        W_IOPS=$(echo $IO_INFO | awk '{print $5}')
        R_MB=$(echo $IO_INFO | awk '{print $6}')
        W_MB=$(echo $IO_INFO | awk '{print $7}')
        UTIL=$(echo $IO_INFO | awk '{print $12}')
        # 检查阈值并告警
        if (( $(echo "$UTIL > $THRESHOLD_UTIL" | bc -l) )); then
            echo "[ALERT] 磁盘 $DISK 使用率过高: ${UTIL}%"
        fi
        # 记录日志
        echo "$(date '+%Y-%m-%d %H:%M:%S'),${R_IOPS},${W_IOPS},${UTIL}%" >> /var/log/disk_io.log
        sleep $INTERVAL
    done
}
monitor_disk_io

使用 iotop 命令

#!/bin/bash
# 使用iotop监控进程级别的IO
# 安装iotop
# apt-get install iotop
# 实时监控
iotop -oP  # 只显示有IO活动的进程
# 批量模式输出
iotop -b -n 3 -oP > /tmp/iotop_output.txt
# 脚本方式
monitor_process_io() {
    iotop -b -n 1 -oP | while read line; do
        PID=$(echo $line | awk '{print $1}')
        DISK_READ=$(echo $line | awk '{print $4}')
        DISK_WRITE=$(echo $line | awk '{print $6}')
        echo "PID: $PID, Read: $DISK_READ, Write: $DISK_WRITE"
    done
}

使用 /proc/diskstats

#!/bin/bash
# 直接从/proc文件系统读取IO数据
# 磁盘设备列表
DISKS=("sda" "sdb" "nvme0n1")
monitor_disk_stats() {
    local disk=$1
    # 读取初始值
    local init=$(awk "/${disk} /" /proc/diskstats | awk '{print $6, $10}')
    local init_read=$(echo $init | awk '{print $1}')
    local init_write=$(echo $init | awk '{print $2}')
    sleep 1
    # 读取1秒后的值
    local final=$(awk "/${disk} /" /proc/diskstats | awk '{print $6, $10}')
    local final_read=$(echo $final | awk '{print $1}')
    local final_write=$(echo $final | awk '{print $2}')
    # 计算IOPS
    local read_iops=$((final_read - init_read))
    local write_iops=$((final_write - init_write))
    echo "$disk: Read ${read_iops} ops/s, Write ${write_iops} ops/s"
}
# 主循环
while true; do
    for disk in "${DISKS[@]}"; do
        monitor_disk_stats $disk
    done
    sleep 1
done

综合监控脚本

#!/usr/bin/env python3
"""
磁盘IO监控脚本 - Python版本
"""
import subprocess
import time
import json
from datetime import datetime
class DiskMonitor:
    def __init__(self, disk_name="sda"):
        self.disk = disk_name
    def get_io_stats(self):
        """获取磁盘IO统计"""
        result = subprocess.run(
            ['iostat', '-x', self.disk, '1', '1'],
            capture_output=True,
            text=True
        )
        lines = result.stdout.strip().split('\n')
        # 解析iostat输出
        for line in lines:
            if self.disk in line:
                stats = line.split()
                return {
                    'timestamp': datetime.now().isoformat(),
                    'disk': self.disk,
                    'r/s': float(stats[3]),
                    'w/s': float(stats[4]),
                    'rkB/s': float(stats[5]),
                    'wkB/s': float(stats[6]),
                    'avgqu-sz': float(stats[8]),
                    'await': float(stats[9]),
                    'svctm': float(stats[10]),
                    'util': float(stats[11])
                }
        return None
    def monitor(self, interval=1, threshold_util=80):
        """持续监控"""
        while True:
            stats = self.get_io_stats()
            if stats:
                # 检查阈值
                if stats['util'] > threshold_util:
                    print(f"[ALERT] 磁盘 {self.disk} 使用率: {stats['util']}%")
                # 输出JSON格式
                print(json.dumps(stats))
                # 记录到文件
                with open('/var/log/disk_io_monitor.log', 'a') as f:
                    f.write(json.dumps(stats) + '\n')
            time.sleep(interval)
# 使用示例
if __name__ == "__main__":
    monitor = DiskMonitor("sda")
    monitor.monitor(interval=2)

告警通知脚本

#!/bin/bash
# 带告警通知的IO监控
# 配置
DISK="sda"
THRESHOLD_IO_UTIL=90
THRESHOLD_IOPS=1000
INTERVAL=5
LOG_FILE="/var/log/disk_io_alerts.log"
EMAIL="admin@example.com"
# 告警函数
send_alert() {
    local message="$1"
    echo "$(date): $message" >> $LOG_FILE
    # 邮件告警
    echo "$message" | mail -s "[IO Alert] $HOSTNAME" $EMAIL
    # 发送到Slack (可选)
    # curl -X POST -H 'Content-type: application/json' \
    #     --data "{\"text\":\"$message\"}" \
    #     YOUR_SLACK_WEBHOOK_URL
}
# 主监控逻辑
while true; do
    # 获取IO数据
    IO_DATA=$(iostat -x $DISK 1 2 | tail -1)
    # 提取指标
    R_IOPS=$(echo $IO_DATA | awk '{print $4}')
    W_IOPS=$(echo $IO_DATA | awk '{print $5}')
    IO_UTIL=$(echo $IO_DATA | awk '{print $12}')
    # 检查告警条件
    if (( $(echo "$IO_UTIL > $THRESHOLD_IO_UTIL" | bc -l) )); then
        send_alert "磁盘 $DISK IO使用率过高: ${IO_UTIL}%"
    fi
    if (( $(echo "$R_IOPS + $W_IOPS > $THRESHOLD_IOPS" | bc -l) )); then
        send_alert "磁盘 $DISK IOPS过高: 读${R_IOPS} 写${W_IOPS}"
    fi
    sleep $INTERVAL
done

使用 dstat 命令

#!/bin/bash
# dstat方式监控
# 安装dstat
# apt-get install dstat
# 显示磁盘IO
dstat -d
# 显示详细磁盘信息
dstat -D sda -d 1 10
# 脚本使用
dstat -d --output /tmp/disk_io.csv 1 3600

Grafana + Prometheus 方案

如果需要长期监控和可视化,建议使用:

# node_exporter 配置
- job_name: 'node'
  static_configs:
    - targets: ['localhost:9100']
# Prometheus 查询
# node_disk_io_time_seconds_total{device="sda"}
# rate(node_disk_io_time_seconds_total{device="sda"}[1m])

监控要点

  1. 关键指标

    • IOPS(每秒IO操作数)
    • 吞吐量(读写速率)
    • 等待时间(await)
    • 队列长度
    • 磁盘使用率
  2. 告警阈值

    • 磁盘使用率 > 80% 告警
    • 等待时间 > 100ms 告警
    • IOPS > 磁盘规格的80%
  3. 优化建议

    • 使用SSD替代HDD提升IOPS
    • RAID配置提高读写性能
    • 调整内核IO调度器

选择最适合你场景的脚本,建议结合多个工具进行综合监控。

抱歉,评论功能暂时关闭!