应使用 /proc/PID/io 中的 write_bytes 字段评估真实磁盘写入吞吐,因其统计内核实际提交到块设备的字节数,绕过 page cache;而 rchar/wchar 仅反映系统调用字节数,含大量缓存命中。

你问的是“通过 /proc/PID/io 中的 read_bytes 评估真实磁盘写入吞吐”——这里有个关键混淆:read_bytes 是读取量,不是写入量。要评估**真实磁盘写入吞吐**,该看的是同一文件里的 write_bytes 字段。
为什么必须用 write_bytes,而不是 rchar 或 wchar
rchar 和 wchar 统计的是进程调用 read(2)/write(2) 的总字节数,包含大量 page cache 命中操作,根本不经过磁盘;而 write_bytes 是内核实际提交到块设备(block device)的字节数,绕过了缓存层,能反映真实落盘压力。
- 比如进程反复
write()同一块内存映射区域,wchar会飙升,但write_bytes可能为 0 - 若进程调用
fsync()或使用O_DIRECT,write_bytes才会显著增长 - 监控后台数据库、日志服务或备份工具时,
write_bytes才是判断“是否真在刷盘”的依据
如何从 /proc/PID/io 提取 write_bytes 值
路径为 /proc/[PID]/io(当前进程可用 /proc/self/io),逐行扫描匹配 write_bytes: 开头的行,提取其后的十进制数值:
- 用
std::ifstream打开文件,避免频繁系统调用开销 - 用
line.rfind("write_bytes:", 0) == 0判断行首匹配,比find()更准 - 定位第一个数字位置后,用
std::stoull()转为uint64_t,防止 32 位截断或溢出 - 务必加
try/catch捕获转换异常(如空值、非数字字符)
怎么算出“每秒写入吞吐”(B/s)
该字段是**累计值**,不能单次读取就得出速率。必须做差分:
- 第一次读取
write_bytes和对应时间戳(推荐std::chrono::steady_clock::now()) - 间隔至少 1 秒后再次读取,计算字节差 Δbytes 和时间差 Δt(秒)
- 吞吐 = Δbytes / Δt,单位是字节/秒(B/s);除以 1024 得 KiB/s,再除 1024 得 MiB/s
- 间隔太短(如 100ms)易得 0(增量未更新);太长(如 10s)会掩盖突发写入峰值
常见陷阱与注意事项
这个方法轻量高效,但有几个现实约束需留意:
- 容器环境里,若 Docker 未启用
--cap-add=SYS_ADMIN或--privileged,/proc/[PID]/io可能不可读或返回 0 - 该值不区分物理介质:SSD、NVMe、虚拟磁盘(如 virtio-blk)都统一上报,无法反推 IOPS 或延迟
- 它只统计本进程发起的写,不包括子进程、线程间共享 fd 的写,也不含内核自发的回写(如 pdflush)
- 不要和
iostat -dx 1的wkB/s直接对比——后者是设备级汇总,前者是进程级归属,二者逻辑层级不同

















