blktrace 采集前需确认内核启用 CONFIG_BLK_DEV_IO_TRACE=y/m,否则报错“Operation not supported”;多核下时间戳非全局同步,须用 blkparse 显式输出 CPU ID 和纳秒偏移;事件 Q→G→I→D→C 对应 IO 各阶段,可定位瓶颈;btt 分析需用原始多文件输入,结合上层工具(如 iotop)才能准确定界问题。

blktrace 采集前必须确认内核是否启用 IO 跟踪支持
很多发行版(尤其是 CentOS/RHEL 7+、Ubuntu 20.04 后)默认关闭 CONFIG_BLK_DEV_IO_TRACE,即使装了 blktrace 工具包也跑不起来。直接执行 blktrace -d /dev/sda 报错 Operation not supported 或静默失败,大概率是这个原因。
检查方法:
zcat /proc/config.gz | grep CONFIG_BLK_DEV_IO_TRACE(若无
/proc/config.gz,查 /boot/config-$(uname -r))。输出应为 CONFIG_BLK_DEV_IO_TRACE=y 或 =m。
- 若为
=m,需先modprobe blk_trace; - 若为
n或未找到,只能换内核或重编译——别试图用echo 1 > /sys/block/sda/trace/enable强行开启,会报错且无效果; - 部分云主机(如 AWS EC2)因使用 NVMe 或虚拟块设备,
/sys/block/xxx/trace/根本不存在,blktrace不适用,得换iosnoop或biotop(bpftrace 实现)。
blkparse 解析时要注意事件时间戳与 CPU 绑定关系
blktrace 输出的原始二进制文件(如 sda.blktrace.0)里,每个事件的时间戳是 per-CPU 的本地 cycle counter,不是 wall-clock 时间。直接用 blkparse -i sda.blktrace.0 看到的 TIME 列是相对起始 trace 的偏移(单位微秒),但多个 CPU 核心的 trace 文件之间**没有全局同步时钟对齐**。
- 多核场景下必须同时采集所有 CPU 的 trace(
blktrace -d /dev/sda -a issue -o sda.trace默认启用 all-cpu 模式); - 解析时用
blkparse -i sda.trace -f "%5T.%9t %5p %2c %5C %5s %5d ] %5S %5N %5I %5P\n"才能看清%C(CPU ID)和%t(纳秒级偏移),否则容易误判“IO 延迟高”其实是跨核调度抖动; - 若想映射回真实时间,需在 trace 开始/结束时用
date +%s.%N打标,并结合/proc/uptime推算,不能依赖blkparse自带的-t参数(它只对单 CPU trace 可靠)。
识别关键 IO 阶段:从 Q → G → I → D → C 的流转含义
blktrace 事件类型(act 字段)直接反映 IO 在 block layer 的生命周期。常见字母含义不是随意记的,而是内核 tracepoint 固定命名:
Linux AI 服务器 — 将 Linux 服务器转换为本地 AI 推理集群。使用 systemd、NVIDIA CUDA 实现无头 Linux AI,零 GUI 开销。
-
Q:IO 进入队列(queue),此时可能被合并、排序、限流(如 cfq/deadline 调度器); -
G:IO 被获取(getrq),调度器已分配 request 结构体,但尚未下发; -
I:IO 被插入调度器队列(issue),注意:这不是发给磁盘,只是“准备好了”,仍可能被延迟(如 iostat 显示的await就含这部分); -
D:IO 下发至设备驱动(driver),真正离开内核 block layer; -
C:IO 完成(complete),驱动回调完成函数,上层可回收 buffer。
典型卡点判断:Q→G 长说明队列深度不足或调度器饥饿;G→I 长说明调度器策略激进(如 bfq 的 idle period);I→D 长说明驱动层有锁竞争或硬件响应慢;D→C 长基本就是磁盘物理延迟(或 NVMe queue full)。
用 blktrace + btt 分析 IO 合并与延迟分布
btt(block trace time)是配套工具,专用于统计各阶段耗时分布,比肉眼扫 blkparse 输出靠谱得多。但它对输入格式敏感:必须用 blktrace -d /dev/sda -o sda 生成的多文件(sda.blktrace.0, sda.blktrace.1…),不能喂单个合并后的文本。
- 正确流程:
blktrace -d /dev/sda -o sda && btt -i sda
; - 关键输出看
Q2Q(两次入队间隔)、Q2G(排队到获取)、Q2C(端到端)的avg和max,尤其注意Q2C> 100ms 且D2C占比低,说明瓶颈在软件栈(如 ext4 journal 锁、dm-thin 元数据); -
btt -l可列出所有 IO 的完整生命周期,但大负载下输出极长,建议加grep "Q2C.*>100"快速定位异常 IO; - 若
btt报错no valid traces found,大概率是 trace 文件权限不对(需 root 读)或路径写错(-i sda不是-i sda.blktrace.0)。
真正难的是把 blktrace 数据和上层应用行为对齐——比如看到大量 Q 事件堆积,得立刻查对应进程的 iotop -o 和 /proc/PID/io,确认是不是某个进程在疯狂 write() 小块数据又没 fsync()。底层 trace 再清晰,脱离上下文也解不了问题。

















