/proc/diskstats

这一节讲磁盘 I/O。核心问题是:

磁盘吞吐、IOPS、磁盘忙不忙,为什么也要靠两次采样差分?

你前面学过:

/proc/stat      -> CPU 累计时间,要两次采样
/proc/loadavg   -> 系统负载
/proc/meminfo   -> 当前内存状态

现在 /proc/diskstats 和 /proc/stat 更像:它里面很多字段也是从开机到现在的累计值,所以要两次采样做差。


1. /proc/diskstats 是什么

一句话:

/proc/diskstats 是 Linux 内核暴露的每块磁盘设备 I/O 统计信息,记录磁盘从系统启动以来完成了多少读写、读写了多少扇区、花了多少时间等。

两篇文章里都提到了 /proc/diskstats:一篇说它是“每块磁盘设备的磁盘 I/O 统计信息列表”,另一篇直接给了 cat /proc/diskstats 的输出示例。


2. 先看一行输出

执行:

cat /proc/diskstats

你可能看到类似:

8       0 sda 62475 31565 6616608 625859 666982 265602 28370898 2977046 0 666856 2741276 0 0 0 0
8       1 sda1 276 0 21216 2990 2 0 2 0 0 444 2736 0 0 0 0
8       5 sda5 61752 31565 6577386 622212 633817 265602 28370896 2928366 0 662648 2695364 0 0 0 0

先不要被一堆数字吓住。你第一阶段只需要看:

设备名
读完成次数
读扇区数
写完成次数
写扇区数
I/O耗时

比如 sda 是整块磁盘,sda1、sda5 是分区。做整盘监控时,一般看 sda、vda、nvme0n1 这种整盘设备,不优先看单个分区。


3. 常用字段怎么理解

简化看,一行大概是:

major minor name reads_completed reads_merged sectors_read time_reading
                  writes_completed writes_merged sectors_written time_writing
                  io_in_progress time_doing_io weighted_time_doing_io

你先记这几个:

字段小白解释可以算什么
name磁盘设备名,比如 sda、vda、nvme0n1区分设备
reads_completed从开机以来完成了多少次读 I/O读 IOPS
sectors_read从开机以来读了多少扇区读吞吐
time_reading读操作累计耗时,通常是毫秒读延迟参考
writes_completed从开机以来完成了多少次写 I/O写 IOPS
sectors_written从开机以来写了多少扇区写吞吐
time_writing写操作累计耗时,通常是毫秒写延迟参考
io_in_progress当前正在进行的 I/O 数当前队列压力
time_doing_io磁盘忙于 I/O 的累计时间磁盘繁忙度
weighted_time_doing_io加权 I/O 时间平均队列长度相关

第一阶段不用把全部字段背死,重点是:完成次数、扇区数、耗时。


4. 为什么 diskstats 也要两次采样

假设你读到:

reads_completed = 100000
sectors_read = 8000000

这不是“当前每秒读了多少”。

它表示:

从系统启动到现在
一共完成了 100000 次读 I/O
一共读了 8000000 个扇区

所以监控系统要做:

第一次读取 /proc/diskstats
    ↓
等待 1 秒或 10 秒
    ↓
第二次读取 /proc/diskstats
    ↓
第二次累计值 - 第一次累计值
    ↓
得到采样窗口内的读写次数和读写字节数

这和 CPU 使用率的思想一样:

累计值本身没意义
差分才代表这一段时间发生了什么

5. 怎么算磁盘吞吐

磁盘吞吐就是:

每秒读/写了多少字节

关键字段:

sectors_read
sectors_written

Linux 里传统扇区大小通常按 512 字节计算。

所以:

read_bytes_delta = (sectors_read_now - sectors_read_prev) * 512
write_bytes_delta = (sectors_written_now - sectors_written_prev) * 512

如果采样间隔是 interval_seconds:

read_Bps = read_bytes_delta / interval_seconds
write_Bps = write_bytes_delta / interval_seconds

换成 MB/s:

read_MBps = read_Bps / 1024 / 1024
write_MBps = write_Bps / 1024 / 1024

6. 手算一个吞吐例子

第一次采样:

sectors_read = 100000
sectors_written = 200000

第二次采样,间隔 1 秒:

sectors_read = 102000
sectors_written = 205000

差分:

read_sectors_delta = 102000 - 100000 = 2000
write_sectors_delta = 205000 - 200000 = 5000

换算字节:

read_bytes = 2000 * 512 = 1,024,000 B
write_bytes = 5000 * 512 = 2,560,000 B

所以:

read ≈ 0.98 MB/s
write ≈ 2.44 MB/s

这就是磁盘读写吞吐。


7. 怎么算 IOPS

IOPS 是:

每秒完成了多少次 I/O 操作。

关键字段:

reads_completed
writes_completed

公式:

read_iops = (reads_completed_now - reads_completed_prev) / interval_seconds
write_iops = (writes_completed_now - writes_completed_prev) / interval_seconds

例子:

第一次:

reads_completed = 1000
writes_completed = 2000

第二次,间隔 1 秒:

reads_completed = 1050
writes_completed = 2080

那么:

read_iops = 50
write_iops = 80

说明这一秒完成了 50 次读 I/O、80 次写 I/O。


8. 吞吐和 IOPS 有什么区别

这两个指标经常一起看。

指标看什么例子
吞吐每秒搬了多少数据100 MB/s
IOPS每秒做了多少次 I/O5000 次/s

区别:

大文件顺序读写:
  吞吐高,IOPS 未必特别高

大量小文件随机读写:
  IOPS 高,吞吐未必高

小白类比:

吞吐 = 一秒搬了多少箱货
IOPS = 一秒跑了多少趟车

一趟车装得多,吞吐就高;一趟车装得少但跑得频繁,IOPS 就高。


9. 怎么粗略看磁盘忙不忙

关键字段:

time_doing_io

它表示磁盘忙于处理 I/O 的累计时间,通常单位是毫秒。

两次采样:

io_time_delta = time_doing_io_now - time_doing_io_prev

如果采样间隔是 1 秒,也就是 1000 ms:

util = io_time_delta / (interval_seconds * 1000)

例子:

1 秒内 time_doing_io 增加了 800 ms

则:

disk_util = 800 / 1000 = 80%

意思是:

这一秒里,磁盘大约有 80% 的时间在处理 I/O。

注意:这个值只能粗略理解成磁盘繁忙度。现代 SSD/NVMe 有并行队列,多队列设备上不能机械地等同于“磁盘一定 80% 饱和”,但面试第一轮这样讲够用。


10. 怎么粗略看读写延迟

可以用:

time_reading / reads_completed
time_writing / writes_completed

但也要做差分。

读平均耗时:

avg_read_latency_ms =
(time_reading_now - time_reading_prev) /
(reads_completed_now - reads_completed_prev)

写平均耗时:

avg_write_latency_ms =
(time_writing_now - time_writing_prev) /
(writes_completed_now - writes_completed_prev)

例子:

1 秒内完成 100 次读
读累计耗时增加 500 ms

则:

avg_read_latency = 500 / 100 = 5 ms

注意边界:

如果 reads_completed_delta = 0,就不能除,要避免除零。

11. 和 /proc/stat、/proc/loadavg 怎么联动

现在你已经有三类指标:

/proc/stat       -> CPU 使用率、iowait
/proc/loadavg    -> 系统任务积压
/proc/diskstats  -> 磁盘吞吐、IOPS、繁忙度、延迟

常见诊断:

现象可能原因
load 高,CPU 不高,iowait 高,disk util 高磁盘 I/O 瓶颈
read/write MB/s 高,但 IOPS 不高大块顺序读写
IOPS 高,但 MB/s 不高小块随机 I/O
Dirty/Writeback 高,write util 高写回压力大
CPU 高,disk util 低主要是计算压力,不是磁盘
load 高,disk util 不高,procs_running 高可能是 CPU 调度压力或线程过多

你可以把它理解成:

loadavg 告诉你有没有排队
stat 告诉你 CPU 是否在等 I/O
diskstats 告诉你磁盘自己到底忙不忙

12. 放到你的性能监控项目里

你的项目本质是 Worker 采集 CPU、内存、磁盘、网络、软中断等指标,Manager 接收后计算健康分、写 MySQL 并提供查询接口;项目资料里也明确 Worker 端有多个采集模块,包含 disk 监控模块,典型采集方式包括磁盘容量、使用率和 I/O 相关指标。

磁盘采集链路可以这样讲:

Worker 定时读取 /proc/diskstats
    ↓
解析目标磁盘的 reads_completed / sectors_read / writes_completed / sectors_written / io_time
    ↓
保存上一轮采样值
    ↓
下一轮采样做差分
    ↓
计算 read_MBps / write_MBps / read_iops / write_iops / disk_util
    ↓
MetricCollector 聚合到 MonitorInfo
    ↓
MonitorPusher 通过 gRPC Push 到 Manager
    ↓
HostManager 纳入健康评分和变化率
    ↓
MySQL 落库,QueryService 查询趋势

这部分和项目主链路一致:Worker 采集指标,MetricCollector 聚合,封装成 Protobuf MonitorInfo,通过 gRPC Push 到 Manager,再由 HostManager 评分、落库、查询。


13. 面试官最可能问什么

13.1 磁盘吞吐怎么计算?

答:

/proc/diskstats 里的 sectors_read 和 sectors_written 是从开机以来的累计扇区数,不是当前速率。监控程序需要两次采样做差,得到采样窗口内读写的扇区数,再乘以扇区大小,通常按 512 字节换算成字节数,最后除以采样间隔,得到 read/write Bps 或 MB/s。


13.2 IOPS 怎么计算?

答:

IOPS 看的是单位时间内完成了多少次 I/O。可以用 /proc/diskstats 中的 reads_completed 和 writes_completed 做两次采样差分,再除以采样间隔,分别得到 read_iops 和 write_iops。


13.3 iowait 高一定是磁盘问题吗?

答:

不一定。iowait 表示 CPU 等待 I/O 的时间,磁盘慢是常见原因,但也可能是网络块存储、文件系统、设备驱动或其他块设备导致。要结合 /proc/diskstats 的磁盘 util、读写延迟、吞吐、IOPS,以及 load average 和阻塞进程数一起判断。


13.4 为什么磁盘指标也要两次采样?

答:

因为 /proc/diskstats 中很多关键字段是累计值,例如完成的读写次数、读写扇区数、读写耗时。单次读取只能知道从开机以来总共发生了多少,不能代表当前速率。两次采样做差,才能得到采样窗口内的吞吐、IOPS 和磁盘繁忙度。


14. 小白最小记忆版

背这个:

/proc/diskstats 看每块磁盘的 I/O 统计。

它里面很多字段是开机以来的累计值,不是当前速率。

磁盘吞吐:
sectors_delta * 512 / interval

IOPS:
completed_delta / interval

磁盘繁忙度:
io_time_delta / (interval * 1000)

load 高 + CPU 不高 + iowait 高 + disk util 高
通常说明磁盘或块 I/O 是瓶颈。

15. 面试版一句话

/proc/diskstats 记录每块磁盘从系统启动以来的 I/O 累计统计,比如完成的读写次数、读写扇区数、读写耗时和 I/O busy time。监控程序不能只读一次,而是要保存上一轮采样值,下一轮做差分。读写吞吐可以用扇区数差值乘以 512 再除以采样间隔,IOPS 可以用完成次数差值除以采样间隔,磁盘繁忙度可以用 I/O busy time 的增量除以采样窗口。我的项目里 Worker 会读取磁盘 I/O 指标,计算后聚合到 MonitorInfo,上报给 Manager 做健康评分和历史趋势分析。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐