Linux监控系统磁盘IO的方法汇总

 更新时间:2026年03月10日 09:36:54   作者:Jinkxs  
在现代分布式系统和高并发服务架构中,磁盘 I/O 性能往往是系统瓶颈的重要来源,本文将从基础命令工具开始,逐步深入到 Java 程序如何集成磁盘监控,最终构建一个完整的自动化监控体系,需要的朋友可以参考下

在现代分布式系统和高并发服务架构中,磁盘 I/O 性能往往是系统瓶颈的重要来源。无论是数据库服务器、日志收集系统,还是缓存层与持久化存储的交互,磁盘读写速度直接决定了整体响应能力。特别是在 Java 应用广泛部署的 Linux 服务器环境中,掌握磁盘 I/O 监控技巧是保障服务稳定性和性能优化的关键。

本文将从基础命令工具开始,逐步深入到 Java 程序如何集成磁盘监控,最终构建一个完整的自动化监控体系。我们将涵盖:

  • Linux 原生命令行工具(iostat, iotop, sar)
  • /proc 和 /sys 文件系统中的 I/O 数据
  • Java 中调用系统命令获取磁盘指标
  • 使用 JMX 暴露自定义磁盘监控 MBean
  • Prometheus + Grafana 构建可视化大盘
  • 告警策略与阈值配置建议
  • 性能调优实战案例

无论你是 DevOps 工程师、Java 后端开发者,还是系统架构师,都能从本文获得实用技能。

为什么需要监控磁盘 I/O?

磁盘 I/O 是系统中最慢的操作之一。相比内存访问(纳秒级)和 CPU 运算(皮秒级),即使是 NVMe SSD 也需要微秒甚至毫秒级别的响应时间。当磁盘成为瓶颈时,会导致:

  • 请求堆积、线程阻塞
  • GC 频率升高(因日志刷盘慢)
  • 数据库写入延迟飙升
  • 服务超时、熔断触发
  • 用户体验下降

根据 Google SRE 手册 中的经验法则:“如果你无法度量它,你就无法改进它。” 因此,建立有效的磁盘 I/O 监控体系,是保障系统 SLA 的第一步。

Linux 原生监控工具概览

1.iostat—— 最常用的 I/O 统计工具

iostat 属于 sysstat 包,提供设备级别的 I/O 统计信息。

# 安装 sysstat(如未安装)
sudo apt install sysstat   # Ubuntu/Debian
sudo yum install sysstat   # CentOS/RHEL

# 查看每秒统计,刷新间隔2秒,共5次
iostat -x 2 5

输出示例:

Device            r/s     w/s     rkB/s     wkB/s   rrqm/s   wrqm/s  %util
sda              8.33    2.50     266.67     80.00     0.00     0.20   1.20
nvme0n1         15.40   12.80    1232.00   1024.00     0.00     0.00   8.90

关键字段解释:

  • r/s, w/s:每秒读/写请求数
  • rkB/s, wkB/s:每秒读/写字节数(KB)
  • %util:设备利用率(接近 100% 表示饱和)

提示:%util 并非绝对性能指标,SSD 多队列并发下即使 %util=100%,也可能未达性能极限。

2.iotop—— 实时进程级 I/O 监控

类似 top,但专注于 I/O:

sudo iotop -oPa

参数说明:

  • -o:仅显示有 I/O 活动的进程
  • -P:仅显示进程(不显示线程)
  • -a:累积模式(显示历史总量)

适合定位“谁在疯狂读写磁盘”。

3.sar—— 历史数据回溯利器

sar 可记录历史 I/O 数据,默认每10分钟采样一次。

# 查看昨天全天磁盘使用情况
sar -d -f /var/log/sysstat/sa$(date -d yesterday +%d)

# 实时查看,每3秒一次
sar -d 3 5

从 /proc 和 /sys 获取原始数据

Linux 内核通过虚拟文件系统暴露大量运行时数据。

/proc/diskstats

每一行代表一个块设备的统计:

cat /proc/diskstats

输出格式(部分字段):

8       0 sda 12345 0 67890 123 4567 0 89012 456 0 579 579

字段含义(按顺序):

  1. 主设备号
  2. 次设备号
  3. 设备名
  4. 读完成次数
  5. 合并读次数
  6. 读扇区数(*512字节)
  7. 读花费毫秒数
  8. 写完成次数
  9. 合并写次数
  10. 写扇区数
  11. 写花费毫秒数

我们可以通过两次采样差值计算实时速率。

/sys/block/[dev]/stat

结构与 /proc/diskstats 类似,但按设备组织:

cat /sys/block/sda/stat

Java 中监控磁盘 I/O —— 基础版

下面我们用 Java 编写一个简单的磁盘监控器,调用 iostat 并解析结果。

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class SimpleDiskMonitor {

    public static void main(String[] args) {
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

        scheduler.scheduleAtFixedRate(() -> {
            try {
                Process process = Runtime.getRuntime().exec("iostat -x 1 1");
                BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));

                String line;
                boolean startReading = false;

                while ((line = reader.readLine()) != null) {
                    if (line.startsWith("Device")) {
                        startReading = true;
                        continue;
                    }
                    if (startReading && !line.trim().isEmpty()) {
                        String[] parts = line.split("\\s+");
                        if (parts.length >= 14) {
                            String device = parts[0];
                            double util = Double.parseDouble(parts[13]);
                            System.out.printf("[%s] Device: %-8s Utilization: %.2f%%%n",
                                    java.time.LocalDateTime.now(), device, util);
                        }
                    }
                }

                process.waitFor();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, 0, 5, TimeUnit.SECONDS);
    }
}

注意:生产环境慎用 Runtime.exec(),存在安全与稳定性风险。建议改用 JNI 或 JNA 调用底层 API。

使用 Sigar 库(已归档,仅作参考)

Sigar(System Information Gatherer And Reporter)曾是流行的跨平台系统监控库,现虽已停止维护,但其设计思想仍具参考价值。

Maven 依赖(若仓库仍有缓存):

<dependency>
    <groupId>org.fusesource</groupId>
    <artifactId>sigar</artifactId>
    <version>1.6.4</version>
</dependency>

示例代码:

import org.hyperic.sigar.DiskUsage;
import org.hyperic.sigar.Sigar;
import org.hyperic.sigar.SigarException;

public class SigarDiskMonitor {
    public static void main(String[] args) throws SigarException, InterruptedException {
        Sigar sigar = new Sigar();

        while (true) {
            String[] devices = sigar.getFileSystemList();
            for (String dev : devices) {
                try {
                    DiskUsage usage = sigar.getDiskUsage(dev);
                    System.out.printf("Device: %s, ReadBytes: %d, WriteBytes: %d%n",
                            dev, usage.getReadBytes(), usage.getWriteBytes());
                } catch (SigarException e) {
                    // 忽略不可读设备
                }
            }
            Thread.sleep(3000);
        }
    }
}

替代方案:推荐使用 OSHI(Operating System and Hardware Information library),活跃维护中。

使用 OSHI 库监控磁盘(推荐)

OSHI 是当前 Java 生态中最活跃的系统信息库,支持 Linux、Windows、macOS。

添加 Maven 依赖:

<dependency>
    <groupId>com.github.oshi</groupId>
    <artifactId>oshi-core</artifactId>
    <version>6.4.4</version>
</dependency>

完整监控示例:

import oshi.SystemInfo;
import oshi.hardware.HWDiskStore;
import oshi.hardware.HardwareAbstractionLayer;

import java.util.Arrays;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class OshiDiskMonitor {

    private static HWDiskStore[] previousDisks = new HWDiskStore[0];

    public static void main(String[] args) {
        SystemInfo si = new SystemInfo();
        HardwareAbstractionLayer hal = si.getHardware();

        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

        scheduler.scheduleAtFixedRate(() -> {
            HWDiskStore[] currentDisks = hal.getDiskStores();

            if (previousDisks.length == 0) {
                previousDisks = currentDisks.clone();
                return;
            }

            long now = System.currentTimeMillis();

            for (int i = 0; i < currentDisks.length; i++) {
                HWDiskStore curr = currentDisks[i];
                HWDiskStore prev = findPreviousDisk(curr.getName());

                if (prev != null) {
                    long timeDiff = now - prev.getTimeStamp();
                    if (timeDiff <= 0) continue;

                    double readBytesPerSec = (curr.getReadBytes() - prev.getReadBytes()) * 1000.0 / timeDiff;
                    double writeBytesPerSec = (curr.getWriteBytes() - prev.getWriteBytes()) * 1000.0 / timeDiff;
                    double transfersPerSec = (curr.getReads() + curr.getWrites() - prev.getReads() - prev.getWrites()) * 1000.0 / timeDiff;

                    System.out.printf("[%s] %-10s | R: %7.2f KB/s | W: %7.2f KB/s | IOPS: %.1f%n",
                            java.time.LocalTime.now(),
                            curr.getName(),
                            readBytesPerSec / 1024,
                            writeBytesPerSec / 1024,
                            transfersPerSec);
                }
            }

            previousDisks = currentDisks.clone();
        }, 0, 2, TimeUnit.SECONDS);
    }

    private static HWDiskStore findPreviousDisk(String name) {
        return Arrays.stream(previousDisks)
                .filter(d -> d.getName().equals(name))
                .findFirst()
                .orElse(null);
    }
}

输出效果:

[14:23:05.123] sda        | R:   128.50 KB/s | W:    64.25 KB/s | IOPS: 15.3
[14:23:07.125] sda        | R:    32.10 KB/s | W:   256.80 KB/s | IOPS: 8.7
[14:23:09.127] nvme0n1    | R:  1024.00 KB/s | W:   512.00 KB/s | IOPS: 120.5

使用 JMX 暴露磁盘指标

为了让监控数据被外部系统(如 Prometheus、Zabbix)采集,我们将其封装为 JMX MBean。

首先定义接口:

public interface DiskMonitorMBean {
    double getReadBytesPerSecond(String deviceName);
    double getWriteBytesPerSecond(String deviceName);
    double getIops(String deviceName);
    String[] getDeviceNames();
}

实现类:

import oshi.SystemInfo;
import oshi.hardware.HWDiskStore;
import oshi.hardware.HardwareAbstractionLayer;

import javax.management.Notification;
import javax.management.NotificationBroadcasterSupport;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class DiskMonitor extends NotificationBroadcasterSupport implements DiskMonitorMBean {

    private final Map<String, HWDiskStore> previousStats = new HashMap<>();
    private final HardwareAbstractionLayer hal;
    private long sequenceNumber = 1;

    public DiskMonitor() {
        this.hal = new SystemInfo().getHardware();
        startSampling();
    }

    private void startSampling() {
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        scheduler.scheduleAtFixedRate(this::sampleDisks, 0, 2, TimeUnit.SECONDS);
    }

    private void sampleDisks() {
        HWDiskStore[] disks = hal.getDiskStores();
        long now = System.currentTimeMillis();

        for (HWDiskStore disk : disks) {
            HWDiskStore prev = previousStats.get(disk.getName());
            if (prev != null) {
                long timeDiff = now - prev.getTimeStamp();
                if (timeDiff > 0) {
                    double rps = (disk.getReadBytes() - prev.getReadBytes()) * 1000.0 / timeDiff;
                    double wps = (disk.getWriteBytes() - prev.getWriteBytes()) * 1000.0 / timeDiff;
                    double iops = (disk.getReads() + disk.getWrites() - prev.getReads() - prev.getWrites()) * 1000.0 / timeDiff;

                    // 发送 JMX 通知(可选)
                    sendNotification(new Notification(
                            "disk.stats.update",
                            this,
                            sequenceNumber++,
                            String.format("Device %s updated: R=%.2f KB/s, W=%.2f KB/s, IOPS=%.1f",
                                    disk.getName(), rps/1024, wps/1024, iops)));
                }
            }
            previousStats.put(disk.getName(), disk);
        }
    }

    @Override
    public double getReadBytesPerSecond(String deviceName) {
        HWDiskStore curr = getDiskByName(deviceName);
        HWDiskStore prev = previousStats.get(deviceName);
        if (curr == null || prev == null) return 0.0;

        long timeDiff = curr.getTimeStamp() - prev.getTimeStamp();
        if (timeDiff <= 0) return 0.0;

        return (curr.getReadBytes() - prev.getReadBytes()) * 1000.0 / timeDiff;
    }

    @Override
    public double getWriteBytesPerSecond(String deviceName) {
        HWDiskStore curr = getDiskByName(deviceName);
        HWDiskStore prev = previousStats.get(deviceName);
        if (curr == null || prev == null) return 0.0;

        long timeDiff = curr.getTimeStamp() - prev.getTimeStamp();
        if (timeDiff <= 0) return 0.0;

        return (curr.getWriteBytes() - prev.getWriteBytes()) * 1000.0 / timeDiff;
    }

    @Override
    public double getIops(String deviceName) {
        HWDiskStore curr = getDiskByName(deviceName);
        HWDiskStore prev = previousStats.get(deviceName);
        if (curr == null || prev == null) return 0.0;

        long timeDiff = curr.getTimeStamp() - prev.getTimeStamp();
        if (timeDiff <= 0) return 0.0;

        return (curr.getReads() + curr.getWrites() - prev.getReads() - prev.getWrites()) * 1000.0 / timeDiff;
    }

    @Override
    public String[] getDeviceNames() {
        return hal.getDiskStores().stream()
                .map(HWDiskStore::getName)
                .toArray(String[]::new);
    }

    private HWDiskStore getDiskByName(String name) {
        return Arrays.stream(hal.getDiskStores())
                .filter(d -> d.getName().equals(name))
                .findFirst()
                .orElse(null);
    }
}

注册 MBean:

import javax.management.MBeanServer;
import javax.management.ObjectName;
import java.lang.management.ManagementFactory;

public class JmxRegistration {
    public static void main(String[] args) throws Exception {
        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
        ObjectName name = new ObjectName("com.example.monitoring:type=DiskMonitor");
        DiskMonitor monitor = new DiskMonitor();
        mbs.registerMBean(monitor, name);

        System.out.println("JMX Disk Monitor registered. Attach with JConsole or VisualVM.");
        Thread.sleep(Long.MAX_VALUE); // keep alive
    }
}

启动后,可用 jconsole 连接本地 JVM,查看磁盘指标。

集成 Prometheus + Grafana

Prometheus 是当前最流行的时序数据库,Grafana 是强大的可视化工具。我们将 Java 应用暴露的 JMX 指标通过 JMX Exporter 导出为 Prometheus 格式。

步骤 1:下载 jmx_exporter

Prometheus JMX Exporter 页面 下载 jmx_prometheus_javaagent.jar(请自行搜索最新官方发布页)。

步骤 2:编写 config.yaml

rules:
- pattern: ".*"

(简单起见,导出所有指标;生产环境应精细化配置)

步骤 3:启动 Java 应用时附加 Agent

java -javaagent:/path/to/jmx_prometheus_javaagent.jar=8081:/path/to/config.yaml \
     -jar your-application.jar

此时访问 http://localhost:8081/metrics 可看到类似:

# HELP com_example_monitoring_DiskMonitor_ReadBytesPerSecond 
# TYPE com_example_monitoring_DiskMonitor_ReadBytesPerSecond gauge
com_example_monitoring_DiskMonitor_ReadBytesPerSecond{deviceName="sda",} 131072.0
com_example_monitoring_DiskMonitor_WriteBytesPerSecond{deviceName="sda",} 65536.0

步骤 4:配置 Prometheus 抓取

prometheus.yml 中添加:

scrape_configs:
  - job_name: 'java-disk-monitor'
    static_configs:
      - targets: ['localhost:8081']

重启 Prometheus。

步骤 5:Grafana 创建仪表盘

添加 Prometheus 数据源,创建新面板,使用 PromQL 查询:

com_example_monitoring_DiskMonitor_ReadBytesPerSecond{deviceName="sda"} / 1024

单位设为 KB/s,即可看到实时曲线图。

mermaid 图表:磁盘监控架构流程

该架构实现了从应用层到告警通道的全链路监控闭环。

告警策略与阈值建议

合理的告警能避免“狼来了”效应。以下是针对磁盘 I/O 的典型告警规则(Prometheus AlertManager 配置):

groups:
- name: disk-alerts
  rules:
  - alert: HighDiskUtilization
    expr: com_example_monitoring_DiskMonitor_Utilization{deviceName=~"sd.*"} > 85
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "High disk utilization on {{ $labels.deviceName }}"
      description: "Disk {{ $labels.deviceName }} has been over 85% utilization for 5 minutes."

  - alert: DiskIOPSLimitApproaching
    expr: com_example_monitoring_DiskMonitor_IOPS{deviceName="nvme0n1"} > 50000
    for: 2m
    labels:
      severity: critical
    annotations:
      summary: "NVMe drive approaching IOPS limit"
      description: "Device nvme0n1 is sustaining >50K IOPS, may impact latency."

  - alert: ZeroDiskActivitySuspicious
    expr: com_example_monitoring_DiskMonitor_ReadBytesPerSecond{deviceName="sdb"} == 0
    for: 10m
    labels:
      severity: warning
    annotations:
      summary: "Disk sdb has zero activity for 10m"
      description: "This may indicate failure or misconfiguration."

告警黄金法则:

  • 相关性:确保告警与业务影响强相关
  • 可操作性:收到告警后知道该做什么
  • 分级制:区分 Warning / Critical
  • 抑制机制:避免重复轰炸

性能调优实战案例

案例一:日志写入导致 %util 飙升

现象:某 Java 服务每隔 5 分钟 %util 达到 95%,GC 暂停时间增加。

诊断

# 使用 iotop 定位进程
sudo iotop -oPa

# 发现 Java 进程在刷日志
Total DISK READ: 0.00 B/s | Total DISK WRITE: 45.23 M/s
  PID  PRIO  USER     DISK READ  DISK WRITE  COMMAND
 1234 be/4  appuser     0.00 B/s   45.23 M/s java -jar app.jar

解决方案

  1. 将日志框架从同步改为异步(Logback AsyncAppender)
  2. 增加日志缓冲区大小
  3. 使用更快的存储介质(如 SSD 专用日志盘)

调整后 Logback 配置:

<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
    <appender-ref ref="FILE"/>
    <queueSize>8192</queueSize>
    <discardingThreshold>0</discardingThreshold>
    <includeCallerData>false</includeCallerData>
</appender>

案例二:数据库写入延迟高

现象:MySQL INSERT 延迟从 2ms 升至 50ms。

排查步骤

# 查看设备详细统计
iostat -xmt 1

# 输出显示 await 很高
Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sdb               0.00     5.00    0.00  200.00     0.00     8.00    81.92     8.00   40.00    0.00   40.00   5.00 100.00

await=40ms 表示平均 I/O 等待时间,远高于正常值(<5ms)。

根因分析

  • 磁盘队列深度(avgqu-sz=8)过高
  • 服务时间(svctm=5ms)尚可,说明是排队导致延迟

优化措施

  1. 调整 I/O Scheduler:echo deadline > /sys/block/sdb/queue/scheduler
  2. 增大 nr_requests:echo 1024 > /sys/block/sdb/queue/nr_requests
  3. 应用层批量提交事务,减少小 I/O

自动化脚本:生成每日磁盘报告

结合 Java 与 Shell,我们可以每天凌晨生成磁盘健康报告。

Java 部分(生成 JSON 数据):

import com.fasterxml.jackson.databind.ObjectMapper;
import oshi.hardware.HWDiskStore;
import oshi.hardware.HardwareAbstractionLayer;
import oshi.SystemInfo;

import java.io.FileWriter;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class DailyDiskReportGenerator {

    public static void main(String[] args) throws Exception {
        SystemInfo si = new SystemInfo();
        HardwareAbstractionLayer hal = si.getHardware();
        HWDiskStore[] disks = hal.getDiskStores();

        List<DiskSummary> summaries = Arrays.stream(disks)
                .map(disk -> new DiskSummary(
                        disk.getName(),
                        disk.getSize(),
                        disk.getReadBytes(),
                        disk.getWriteBytes(),
                        disk.getReads(),
                        disk.getWrites()))
                .collect(Collectors.toList());

        ObjectMapper mapper = new ObjectMapper();
        String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(summaries);

        String filename = String.format("/var/log/disk-report-%s.json", LocalDate.now());
        try (FileWriter fw = new FileWriter(filename)) {
            fw.write(json);
        }

        System.out.println("Report written to: " + filename);
    }

    static class DiskSummary {
        public String name;
        public long size;
        public long totalReadBytes;
        public long totalWriteBytes;
        public long totalReads;
        public long totalWrites;

        public DiskSummary(String name, long size, long totalReadBytes, long totalWriteBytes, long totalReads, long totalWrites) {
            this.name = name;
            this.size = size;
            this.totalReadBytes = totalReadBytes;
            this.totalWriteBytes = totalWriteBytes;
            this.totalReads = totalReads;
            this.totalWrites = totalWrites;
        }
    }
}

Shell 脚本(/etc/cron.daily/disk-report):

#!/bin/bash

# 设置 Java 环境
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
export PATH=$JAVA_HOME/bin:$PATH

cd /opt/disk-monitor
java -cp "lib/*:target/*" DailyDiskReportGenerator

# 可选:发送邮件或上传到对象存储
# mail -s "Daily Disk Report" admin@company.com < /var/log/disk-report-$(date +%Y-%m-%d).json

赋予执行权限:

sudo chmod +x /etc/cron.daily/disk-report

单元测试你的监控逻辑

良好的监控代码也应具备可测试性。

import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

import static org.junit.jupiter.api.Assertions.assertTrue;

public class DiskMonitorTest {

    @Test
    public void testCalculateReadRate() {
        HWDiskStore mockPrev = Mockito.mock(HWDiskStore.class);
        HWDiskStore mockCurr = Mockito.mock(HWDiskStore.class);

        Mockito.when(mockPrev.getReadBytes()).thenReturn(1024L);
        Mockito.when(mockCurr.getReadBytes()).thenReturn(5120L); // +4096 bytes
        Mockito.when(mockPrev.getTimeStamp()).thenReturn(1000L);
        Mockito.when(mockCurr.getTimeStamp()).thenReturn(3000L); // 2 seconds later

        double rate = (mockCurr.getReadBytes() - mockPrev.getReadBytes()) * 1000.0 /
                     (mockCurr.getTimeStamp() - mockPrev.getTimeStamp());

        assertTrue(Math.abs(rate - 2048.0) < 0.01); // 2048 bytes/sec
    }

    @Test
    public void testZeroTimeDiffReturnsZero() {
        HWDiskStore mockPrev = Mockito.mock(HWDiskStore.class);
        HWDiskStore mockCurr = Mockito.mock(HWDiskStore.class);

        Mockito.when(mockPrev.getTimeStamp()).thenReturn(1000L);
        Mockito.when(mockCurr.getTimeStamp()).thenReturn(1000L);

        double rate = (mockCurr.getReadBytes() - mockPrev.getReadBytes()) * 1000.0 /
                     (mockCurr.getTimeStamp() - mockPrev.getTimeStamp());

        assertTrue(Double.isNaN(rate) || rate == 0.0);
    }
}

云端环境注意事项

在 AWS EC2、阿里云 ECS 等云主机上,磁盘 I/O 行为略有不同:

  • EBS 卷:有基准 IOPS 限制,突发型实例使用积分制
  • 实例存储:高性能但临时性,重启即丢失
  • 网络延迟:云盘本质是网络存储,延迟高于本地 SSD

监控建议:

  • 同时监控 CloudWatch 或云厂商原生监控
  • 关注 BurstBalance(突发积分余额)
  • 对比 iostat 与云监控数据,验证一致性

AWS CLI 示例:

aws cloudwatch get-metric-statistics \
    --namespace AWS/EBS \
    --metric-name VolumeReadBytes \
    --dimensions Name=VolumeId,Value=vol-1234567890abcdef0 \
    --start-time $(date -u -d '1 hour ago' '+%Y-%m-%dT%H:%M:%SZ') \
    --end-time $(date -u '+%Y-%m-%dT%H:%M:%SZ') \
    --period 300 \
    --statistics Sum

未来演进方向

随着 eBPF、io_uring 等新技术普及,磁盘监控也在进化:

  • eBPF:无需修改内核即可追踪 I/O 路径,开销极低
  • io_uring:异步 I/O 新接口,需适配监控工具
  • OpenTelemetry:统一观测性标准,未来可能替代部分 JMX/Prometheus

总结

磁盘 I/O 监控不是一次性任务,而是持续优化的过程。我们从基础命令出发,逐步构建了:

  1. 实时监控(iostat/iotop)
  2. 程序集成(Java + OSHI)
  3. 标准化暴露(JMX → Prometheus)
  4. 可视化与告警(Grafana + AlertManager)
  5. 自动化报告
  6. 性能调优闭环

记住几个关键原则:

🔹 监控一切,但只告警重要的事
🔹 指标要可聚合、可对比、可预测
🔹 与业务指标联动(如“磁盘延迟上升 → 订单处理变慢”)
🔹 定期回顾告警有效性,删除噪音规则

以上就是Linux监控系统磁盘IO的方法汇总的详细内容,更多关于Linux监控系统磁盘IO的资料请关注脚本之家其它相关文章!

相关文章

  • CentOS 设置默认JDK步骤详解及命令

    CentOS 设置默认JDK步骤详解及命令

    这篇文章主要介绍了 CentOS 设置默认JDK步骤详解及命令的相关资料,这里对配置Java的环境进行了详细的介绍,需要的朋友可以参考下
    2016-11-11
  • Linux开机自启动服务两种方式介绍

    Linux开机自启动服务两种方式介绍

    大家好,本篇文章主要讲的是Linux开机自启动服务两种方式介绍,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览
    2021-12-12
  • Linux使用Curl进行网络请求的详细教程

    Linux使用Curl进行网络请求的详细教程

    Curl是一个强大的命令行工具,用于在Linux环境中进行数据传输,支持多种协议,包括HTTP、HTTPS、FTP等,Curl的灵活性使其成为进行网络请求的首选工具,本文将详细介绍如何使用Curl进行不同类型的网络请求,需要的朋友可以参考下
    2025-06-06
  • Linux(CentOS7)使用 RPM 安装 mysql 8.0.11的教程

    Linux(CentOS7)使用 RPM 安装 mysql 8.0.11的教程

    这篇文章主要介绍了Linux(CentOS7)使用 RPM 安装 mysql 8.0.11的教程,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-03-03
  • apache伪静态与iis伪静态规则与配置区别介绍

    apache伪静态与iis伪静态规则与配置区别介绍

    本文章来总结一下关于apache伪静态与iis伪静态区别介绍,主要讲到了一些规则的问题与配置区别,以后大家就可以直接在iis伪静态转换apache,反之也很简单哦,需要了解的碰可以参考下
    2012-12-12
  • 让Apache支持cgi、SSI、shtml的配置方法

    让Apache支持cgi、SSI、shtml的配置方法

    配置Apache支持cgi、SSI、shtml,供大家学习参考
    2013-02-02
  • Linux 文件内容相关命令使用汇总

    Linux 文件内容相关命令使用汇总

    Linux操作系统有很多强大的文件内容相关命令,这些命令可以让您查看、分析和编辑文件。其中,最基本和常用的命令包括cat、more、less和head/tail等。除了这些基本命令之外,grep和find命令也是文件搜索和过滤方面的有力工具。
    2023-04-04
  • Vagrant基本命令使用详解

    Vagrant基本命令使用详解

    本篇文章主要介绍了Vagrant基本命令详解,现在分享给大家,也给大家做个参考。感兴趣的小伙伴们可以参考一下。
    2016-11-11
  • Linux系统内存不足导致服务崩溃的排查方法

    Linux系统内存不足导致服务崩溃的排查方法

    Linux 系统内存不足会导致服务崩溃、系统变慢甚至无法正常运行,以下是内存不足问题的详细排查方法,包括问题症状、原因分析及解决步骤,
    2025-08-08
  • Linux下如何挂载磁盘的方法示例

    Linux下如何挂载磁盘的方法示例

    这篇文章主要介绍了Linux下如何挂载磁盘的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09

最新评论