/proc/diskstats不直接提供写入延迟,需通过两次采样计算:平均写延迟(ms)= write_ticks增量 ÷ writes_completed增量;它仅统计已完成写请求的设备层累计耗时,不含排队中或合并的请求。

什么是/proc/diskstats里能拿到的写延迟数据
它本身不直接提供“写入延迟”(单位毫秒),只记录累计写入扇区数、完成写请求数、写花费的毫秒总数等基础计数器。所谓“实时写入延迟”,必须靠两次采样差值计算:平均延迟 = write_ticks增量 ÷ writes_completed增量。注意,write_ticks是设备层累计耗时(毫秒),不是单次IO耗时,且仅统计已**完成**的写请求——排队中或被合并的请求不计入。
如何从/proc/diskstats提取目标磁盘的6个关键字段
每行对应一个设备,字段顺序固定(内核文档保证)。以sda为例,需定位其行并取第3–8列(基于0索引):
8 0 sda 2456789 1234 9876543 45678 3456789 2345 8765432 67890 0 0 0
对应含义(按顺序):
-
reads_completed(第3列) -
reads_merged(第4列) -
sectors_read(第5列) -
read_ticks(第6列) -
writes_completed(第7列) -
write_ticks(第8列)
实操建议:
- 用
std::ifstream逐行读/proc/diskstats,std::string::find()匹配设备名(如"sda "带空格防误匹配sda1) - 用
std::istringstream解析该行,跳过前2列(主/次设备号),再取后续6个unsigned long long - 不要依赖列名或注释行——
/proc/diskstats无header,且不同内核版本字段数一致,但语义不变
两次采样间如何安全计算增量与平均延迟
核心陷阱:计数器会回绕(unsigned long long溢出概率低但非零),且writes_completed可能为0(无新写完成),此时除零崩溃或结果失真。
实操建议:
- 用两个结构体存上次和本次采样值,字段全为
unsigned long long - 增量计算用
if (curr.writes_completed >= last.writes_completed) delta_writes = curr.writes_completed - last.writes_completed;,否则视为回绕→跳过本次计算 - 仅当
delta_writes > 0时才算延迟:double avg_write_latency_ms = static_cast<double>(delta_write_ticks) / delta_writes;</double> - 采样间隔建议≥1秒:太短则
delta_writes常为0;太长则实时性下降。可用std::this_thread::sleep_for(1s)控制
C++代码里容易漏掉的兼容性细节
Linux内核版本差异会影响字段含义。例如5.10+新增了io_ticks和time_in_queue,但/proc/diskstats原有11列结构未变,前8列语义稳定。真正要警惕的是设备命名:
- 云环境常见
nvme0n1,字段位置相同,但名字含'n'和'1',匹配时别写死"sda"字符串 - LVM或md设备如
dm-0,需确认是否在/proc/diskstats中可见(默认可见,但某些发行版可能过滤) - 容器场景下,宿主机
/proc/diskstats仍可读,但cgroup限速不影响该文件数值——它反映的是物理设备真实负载
最易被忽略的一点:write_ticks包含IO调度器排队时间和实际设备处理时间,无法区分“慢盘”还是“高并发排队”。如果需要精确到硬件层延迟,得配合blktrace或perf,/proc/diskstats只适合宏观趋势监控。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











