不能。docker stats 默认只显示 block i/o 累计读写字节数,不提供实时带宽(mb/s)或 iops,需手动采集两次差值并换算;而 iostat -x 1 可直接获取设备级真实 io 性能指标。

docker stats 能不能直接看到磁盘IO带宽?
不能。docker stats 默认不显示磁盘读写带宽(即 MB/s、IOPS),它只输出 CPU、内存、网络收发量和存储驱动层的累计字节数(如 blkio.io_service_bytes_recursive 的原始值),但不作速率换算。你看到的 MEM USAGE / LIMIT 和 NET I/O 是实时速率,而磁盘部分只有总量,没有“每秒多少MB”这种关键压测指标。
怎么从 docker stats 获取实时磁盘读写速率?
需要手动采集两次 docker stats --no-stream --format 的输出,间隔固定时间(比如 1 秒),再用差值除以时间算出带宽。核心是提取容器的 blkio.io_service_bytes_recursive 中的 Read 和 Write 字段 —— 它们在 /sys/fs/cgroup/blkio/docker/<container-id>/blkio.io_service_bytes_recursive</container-id> 下可查,docker stats 本身不直接暴露这些字段,得绕路:
- 先用
docker inspect <container-name> -f '{{.Id}}'</container-name>拿到容器 ID - 再读取 cgroup 文件:
cat /sys/fs/cgroup/blkio/docker/<id-short>/blkio.io_service_bytes_recursive 2>/dev/null | grep "Read\|Write"</id-short> - 脚本中每 1s 采集一次,解析出 Read 和 Write 的字节数,做差值后除以 1024² 得 MB/s
注意:该路径依赖 cgroup v1 + blkio 子系统启用,Docker 默认用 systemd 启动时可能挂载在 /sys/fs/cgroup/blkio/system.slice/docker-<full-id>.scope/</full-id>,需用 systemd-cgls 或 find /sys/fs/cgroup/blkio -name "*docker*" -type d 2>/dev/null 定位真实路径。
为什么 iostat 比 docker stats 更适合 IO 压测监控?
因为 iostat -x 1 直接给出设备级的 rMB/s、wMB/s、%util、await 等真实 IO 性能指标,且不受容器抽象层干扰。对 IO 压测而言,你真正要验证的是底层块设备(如 sda 或 nvme0n1)能否扛住压力,而不是容器“声称”写了多少 —— 尤其当使用 overlay2 时,写放大、page cache、buffer dirty ratio 都会影响最终落盘行为。
- 在宿主机运行:
iostat -x -d 1 | grep -E "(nvme|sd|vd)" - 若压测容器绑定了特定设备(如通过
--device /dev/nvme0n1:/dev/nvme0n1:rwm),就盯那个设备 - 注意区分
rMB/s(物理读)和rrqm/s(合并读请求数),后者高说明 IO 请求碎片化严重
用 docker run 启动压测容器时,哪些参数影响 IO 统计准确性?
三个关键点常被忽略:
-
--storage-opt size=不影响 IO 带宽统计,但若设太小导致频繁触发 overlay2 的 copy-up 或空间满,会引发ENOSPC错误,让压测中途失败,统计失真 -
--memory限制过低会导致内核频繁回收 page cache,使iostat显示的wMB/s异常升高(cache 回写激增),掩盖真实应用 IO 模式 - 没加
--read-only却在容器里跑 fio 写临时文件?那大量 IO 其实消耗在 overlay2 的 upperdir 写入上,不是目标设备,iostat看不到,blkiocgroup 却会计 —— 这种错位会让数据不可比
压测前务必确认:目标设备是否直通、page cache 是否预热、cgroup blkio 是否启用、以及你到底想测容器封装层还是裸设备 —— 这三者对应的监控手段完全不同。











