qcow2 raw 区别:同一份镜像四种格式(qcow2/raw/vmdk/vdi)实测对照
本篇是 SoC 与 QEMU 入门路线的第 06 篇。如果「宿主机、客户机、磁盘镜像」这些词还陌生,建议先读第 01 篇 认识 QEMU:从零看懂虚拟机、镜像与快照,建立「镜像就是宿主机上的一个文件」这个基本认知。
前面几篇已经把 QEMU 自家的 qcow2 摸了一遍:第 03 篇 qemu-img create/info/convert 实操 讲了创建、体检与互转,第 04 篇 qcow2 扩容、压缩与快照管理 讲了快照与空间回收,第 05 篇 qcow2 后端文件与克隆 讲了 backing file 增量链。但虚拟机世界并不只有 qcow2:VMware 的 vmdk、VirtualBox 的 vdi、最朴素的 raw,在下载系统镜像、对接虚拟化平台、导出 OVA 时都会碰到。本篇不做纸面翻译,而是把同一份镜像转成四种格式,用真机输出回答一个问题:它们占的地方为什么不一样,什么场景该选谁。
本文要回答的问题
- 同一份 64MiB 镜像,qcow2、raw、vmdk、vdi 四种格式在宿主机上各占多少空间?
- 为什么 raw 文件表观长度是 64MiB,真实占用却只有 8MiB?
- vdi 的
cluster_size为什么是 1MiB,而另外三家都是 64KiB? - vmdk 输出里的
cid、parent cid、monolithicSparse字段说明了什么? - 日常开发、性能测试、VMware/VirtualBox 协作分别该选哪种镜像格式?
一、实验设计:一个数据源,四次变身
做格式对照最忌讳拿四个来历不同的镜像互相比——写入量不同、文件系统不同,比出的数字没有意义。本篇的实验只建一个数据源:先用 qemu-img create 建一个 64MiB 的 qcow2 镜像,再用 qemu-io 从零偏移写入 8MiB 的固定字节 0x55,让四种格式面对完全相同的盘面——64MiB 虚拟容量、前 8MiB 是确定数据、后 56MiB 全零未写。随后用三条 qemu-img convert -O 分别转出 vmdk、vdi、raw,最后对四个产物逐个 du -h 加 qemu-img info。
读这张对比卡先抓住一条主线:四家的 virtual size 全部是 64 MiB,没有任何转换动过 Guest 看到的盘面;真正分家的是宿主机真实占用与封装方式。绿色一栏是本篇最终推荐的日常主力,灰色一栏是机制最透明的基准格式,橙色一栏的两种格式价值在各自的虚拟化生态。卡片里的每个数字后面都会用终端实录逐条兑现。
二、建源与三连转:convert 到底做了什么
下面的终端实录是实验第一段:建 qcow2 源盘、写入 8MiB 固定字节,再连续三条 convert。注意三条转换命令没有任何报错或进度输出——qemu-img convert 是流式离线读写,顺着源格式的映射把 Guest 盘面逐扇区重放出来,再按目标格式的规则重新封装。
create 的回显行值得停一下:fmt=qcow2 cluster_size=65536 ... compression_type=zlib size=67108864,簇大小 64KiB、压缩算法 zlib、容量 67108864 字节(正好 64MiB)。qemu-io -c write -P 0x55 0 8M 从偏移 0 写入 8MiB 的 0x55 模式字节,回显 wrote 8388608/8388608 bytes 确认一字节没少。三条 convert 静默完成后,目录里就有了四个同根同源的镜像文件,接下来的 info 对照全部基于它们。
三、四个 info 并排读:尺寸分家、字段各异
先看 qcow2 与 vmdk 这一对。两个文件的 virtual size 都是 64 MiB(67108864 bytes),但 disk size 一个是 8.31 MiB、一个是 8.06 MiB;du -h 的口径分别是 8.3M 和 8.1M,与 info 互相印证。
qcow2 这一段的格式专有信息最厚:compat: 1.1、compression type: zlib、refcount bits: 16、extended l2: false,加上文件头与 L1/L2 映射表,这些元数据即使只写了 8MiB 数据也必须落盘,构成它比 raw 多出约 0.31MiB 的「元数据税」。vmdk 这一段则暴露了 VMware 谱系管理的设计:cid: 3970712119 是本镜像的内容标识,parent cid: 4294967295(即 32 位全 1,等价于「无父镜像」)用于增量盘回溯父盘,create type: monolithicSparse 表示单文件稀疏形态——vmdk 还有可拆成多个 extent 文件的形态,这里转换出来的是最常用的单体稀疏款。两者 cluster_size 都是 65536,内部分配粒度一致。
再看 vdi 与 raw 这一对,反差更有意思。
vdi 的 cluster_size: 1048576 是 1MiB,与另外三家的 64KiB 差了十六倍。这是 VirtualBox 的默认策略:簇越大,映射表越小、顺序 I/O 的元数据查表次数越少,代价是小写入也会按 1MiB 粒度分配,随机小写场景容易浪费空间。本次实验写入的是连续 8MiB,恰好整簇对齐,所以 vdi 的 disk size 恰好 8 MiB(file length 8389632 字节里只多出不到 1KB 的头部),元数据开销反而是四家里最薄的。raw 这一段最能说明「裸格式」的含义:它没有 cluster_size 字段,也没有任何 Format specific information 节,file length: 64 MiB (67108864 bytes) 与 disk size: 8 MiB 同时出现——文件名义上有 64MiB 长,但后 56MiB 在 APFS 上是以空洞(hole)存在的,不分配任何磁盘块,du 因此只报 8.0M。raw 的稀疏性完全是文件系统给的,格式本身一个字节的元数据都不贡献。
读这四段 info 输出可以固定一个顺序,拿到任何来历不明的镜像都照此体检:先看 file format 确认封装,再看两个尺寸判断写了多少数据,最后看格式专有字段评估快照、压缩与谱系能力。本次四个文件的虚拟容量清一色 67108864 字节,证明 convert 只换封装、不动盘面;而真实占用从 8.0M 到 8.3M 的微小差距,恰好把各格式元数据的厚薄按顺序排了出来。
四、差异从哪来:三层原因拆解
把四个产物摆在一起,占用数字的差异可以拆成三个来源。第一层是元数据税:qcow2 最贵(8.31MiB 对 8MiB 数据,约 4% 的额外开销),因为它要维护文件头、L1/L2 映射、引用计数表等一整套支持快照与压缩的结构;vmdk 次之(8.06MiB),开销花在 cid 谱系与 extent 描述上;vdi 头部最轻;raw 为零。第二层是分配粒度:qcow2、vmdk 按 64KiB 簇分配,vdi 按 1MiB 块分配,raw 则把粒度问题完全交给文件系统块。连续大写大家都对齐,看不出差距;一旦换成大量零散小写,粗粒度的 vdi 会明显胖得更快。第三层是稀疏机制的归属:三种容器格式在自己文件内部维护映射,拷到任何文件系统、甚至流式传输后依然保持稀疏;raw 的稀疏依赖宿主文件系统打洞,某些拷贝路径(不带稀疏感知的 cp、管道重定向)会把空洞展开成真实零字节,64MiB 立刻实打实地占满,这是用 raw 最常踩的坑。
由此得到两条实操纪律。其一,评估镜像占地方一律以 du -h 或 info 里的 disk size 为准,ls -lh 的表观长度对四种格式都是 64MiB 量级,拿它估磁盘余量必然误判。其二,跨机器搬运 raw 镜像优先用 qemu-img convert 或带稀疏感知的拷贝方式,落到不支持空洞的文件系统(比如某些 FAT/exFAT U 盘)前要有它会整体膨胀的心理准备;容器格式则没有这个负担,这也是 qcow2 在日常开发里更省心的原因之一。
| 维度 | qcow2 | raw | vmdk | vdi |
|---|---|---|---|---|
| 实测 disk size(同源 8MiB 数据) | 8.31 MiB | 8 MiB | 8.06 MiB | 8 MiB |
| 实测 du 占用 | 8.3M | 8.0M | 8.1M | 8.0M |
| 分配粒度 | 64 KiB 簇 | 靠文件系统块 | 64 KiB 簇 | 1 MiB 块 |
| 稀疏来源 | 容器内 L2 映射 | 文件系统空洞 | 容器内 grain 映射 | 容器内块映射 |
| 格式专有元数据 | 最厚(快照/压缩/引用计数) | 无 | cid 谱系、extent 描述 | 轻量头部 |
| 原生快照 | 支持 | 不支持 | 支持(快照链) | 支持(VirtualBox 内) |
| 压缩 | zlib/zstd | 不支持 | 有限支持 | 不支持 |
| 兼容生态 | QEMU、OpenStack、libvirt | 全平台通吃 | VMware、OVA 导出 | VirtualBox |
| 典型用途 | 日常开发、模板克隆、快照回滚 | 性能基准、共享块设备 | VMware 协作与虚拟机分发 | VirtualBox 虚拟机磁盘 |
这张表的维度都对着选型决策:先看生态归属排除两家,再在剩下的里按「要不要快照、要不要极致 I/O、要不要跨文件系统保稀疏」取舍。
五、选型决策:什么场景选什么格式
机制讲完,落到决策。下图把选型过程画成一棵判定树:红色是入口判定,绿色是推荐主力 qcow2,橙色是三个各有明确生态或性能归属的格式。读图时先问自己「镜像要在哪个平台跑、要不要快照」,顺着边标签走就能落到唯一答案。
四条分支的结论可以直接照用。第一,QEMU 环境下默认选 qcow2,本篇实测它为 8MiB 数据多付约 0.31MiB 元数据税,换来的是原生快照、压缩、backing file 克隆和跨文件系统保稀疏,日常开发这笔税非常划算;快照与压缩的具体操作见第 04 篇 qcow2 扩容、压缩与快照管理,克隆链路见第 05 篇 qcow2 后端文件与克隆。第二,跑性能基准或对接 Ceph、LVM、裸块设备时选 raw,它没有映射层、I/O 路径最短,测出来的数字不被格式开销污染,但要用 cp -p 或 qemu-img convert 搬运,别让空洞被展开。第三,需要交付 VMware 环境或打包 OVA 时选 vmdk,qemu-img convert -O vmdk 一条命令即可产出,cid 谱系字段让它在 VMware 的增量体系里能被正确识别。第四,团队统一在 VirtualBox 上协作时选 vdi,享受原生管理界面与最轻的头部,但要记住它 1MiB 的粗粒度不适合密集小写场景。四种格式之间互转无损且虚拟容量不变,所以选型不是一锤子买卖:拿不准就先用 qcow2,交付前按目标平台 convert 出去。
这一篇在知识体系里的位置
本篇是 SoC 与 QEMU 入门路线的格式横向篇:上承第 03 篇 qemu-img create/info/convert 实操 建立的两个尺寸与稀疏分配概念,把对照范围从 qcow2/raw 两家扩到四家;与第 04 篇 qcow2 扩容、压缩与快照管理、第 05 篇 qcow2 后端文件与克隆 构成「横看格式选型、纵看 qcow2 能力」的组合。零基础入口始终是第 01 篇 认识 QEMU:从零看懂虚拟机、镜像与快照。再往底层走,QEMU 如何把镜像里的 Guest 扇区请求接到块设备与 virtio 总线,可以结合 QEMU/TCG 与功能平台 的设备模型视角理解。
代码获取:本篇全部实验的可复现脚本见公开仓库 derekzhuo/geek-doc.cn 的
experiments/qemu-qcow2-basics目录。克隆后进入该目录执行./run-all.sh可跑完全部实验,或单独执行./04-formats-compare.sh只复现本篇的四格式对照,终端输出与本篇实录逐条对应。
实验环境
- 机器/系统:MacBook Pro(Intel x86_64)/ macOS 26
- 工具版本:qemu-img 11.1.2(QEMU 11.1.2,Homebrew 安装)
- 日期:2026-11-07
- 完整命令序列:实验脚本
./04-formats-compare.sh(整套run-all.sh流程中的第 4 个脚本),内部依次执行qemu-img create -f qcow2 base.qcow2 64M→qemu-io -c write -P 0x55 0 8M base.qcow2→qemu-img convert -O vmdk base.qcow2 disk.vmdk→qemu-img convert -O vdi base.qcow2 disk.vdi→qemu-img convert -O raw base.qcow2 disk.raw→ 对四个文件分别执行du -h与qemu-img info对照
总结
qcow2 raw 区别的本质是「带映射的容器」与「裸盘逐字节映像」之分:同一份 64MiB 虚拟容量、预写 8MiB 数据的镜像,qcow2 实占 8.31MiB(元数据最厚、64KiB 簇、快照压缩克隆能力齐全),raw 实占 8MiB 且无任何格式元数据、稀疏全靠 APFS 空洞,vmdk 实占 8.06MiB 并带 cid 谱系服务 VMware 生态,vdi 实占 8MiB 但采用 1MiB 粗粒度块。选型记住四句话:QEMU 日常用 qcow2,性能基准与裸块用 raw,VMware/OVA 用 vmdk,VirtualBox 用 vdi;格式之间 convert 无损、虚拟容量不变,先 qcow2 打底、交付前按平台转换是最稳妥的工作流。