QCOW2/RAW/qemu-img 概念浅析

简介: 目录目录扩展阅读RAWQCOW2 QEMU-COW 2QCOW2 HeaderQCOW2 的 COW 特性QCOW2 的快照qemu-img 的基本使用RAW 与 QCOW2 的区别扩展阅读The QCOW2 Image F...

目录

扩展阅读

The QCOW2 Image Format
为什么用ls和du显示出来的文件大小有差别?
Qcow2镜像格式解析  
ROW/COW 快照技术原理解析

RAW

KVM 虚拟化中使用的镜像格式通常为 RAW 和 QCOW2 两种格式.

RAW 的原意是「未被加工的」, 所以 RAW 格式镜像文件又被称为 原始镜像裸设备镜像, 从这些称谓可以看出, RAW 格式镜像文件能够直接当作一个块设备, 以供 GuestOS 使用. 也就是说 KVM 的 GuestOS 可以直接从 RAW 镜像中启动, 就如 HostOS 直接从硬盘中启动一般.

块设备: IO 设备中的一类, 将信息存储在固定大小的块中, 并且每个块都有自己的地址, 常用的块设备有硬盘.

因为 RAW 镜像文件赤裸裸的特性带来了下列好处:

  • 使用 dd 指令创建一个 File 就能够模拟 RAW 镜像文件
  • 性能较 QCOW2 要更高
  • 支持裸设备的原生特性, 例如: 直接挂载
  • 能够随意转换格式, 甚至作为其他两种格式转换时的中间格式
  • 能够使用 dd 指令来追加 RAW 镜像文件的空间

相对的, RAW 镜像文件也具有一个非常大的缺陷, 就是不支持快照. 所以才有了后来 QCOW 和 QCOW2 的发展.

QCOW2 (QEMU-COW 2)

(摘自官方文档)QEMU copy-on-write format with a range of special features, including the ability to take multiple snapshots, smaller images on filesystems that don’t support sparse files, optional AES encryption, and optional zlib compression
QEMU-COW 镜像文件具有一系列特性, 支持包括 多重快照(能够创建基于之前镜像的新镜像, 速度更快), 占用更小的存储空间(不支持稀疏特性, 不会预先分配指定 Size 的存储空间), 可选的 AES 加密方式, 可选的 zlib 压缩方式 等功能.

QCOW2 镜像格式是 KVM-QEMU 支持的磁盘镜像格式之一, 其表现形式为在一个系统文件中模拟一个具有一定 Size 的块设备.

QCOW2 Header

每个 QCOW2 镜像文件都会以一个格式固定的 Header 开始.

  typedef struct QCowHeader {
      uint32_t magic;
      uint32_t version;
      # Version number 版本号 (valid values are 2 and 3)

      uint64_t backing_file_offset;
      # backing_file_offset: 表示 backing file 文件绝对路径的字符串相对于 QCOW2 镜像文件起始位置的偏移量  

      uint32_t backing_file_size;
      # 因为上述的 backing file 文件绝对路径的字符串不是以'\0'结束的
      # 所以需要通过 backing_file_size 来指出该字符串的长度
      # 如果当前 Header 的镜像是一个 COW 镜像, 则存在 backing file 文件, 否则没有

      uint32_t cluster_bits;
      # cluster_bits: cluster 的位数, 表示 cluster 的大小
      # 1 << cluster_bits (1 向左移 cluster_bits 位得到的就是 cluster 的大小)
      # 一般是 512 byte <= cluster_bits <= 2 MB

      uint64_t size; /* in bytes */
      # size: 镜像文件以块设备呈现时的 Size(byte)

      uint32_t crypt_method;
      # crypt_method: 1 表示开启采用了 AES 加密;0 表示没有加密

      uint32_t l1_size;
      # L1 table(1 级索引) 可用的 8 字节项个数

      uint64_t l1_table_offset;
      # L1 table 相对于镜像文件在存储中起始位置的偏移量, 需要与 cluster 对齐

      uint64_t refcount_table_offset;
      # refcount table(引用计数表) 相对于镜像文件在存储中起始位置的偏移量, 需要与 cluster 对齐

      uint32_t refcount_table_clusters;
      # refcount table 占用多少个 cluster

      uint32_t nb_snapshots;
      # 镜像文件中所包含的快照数量

      uint64_t snapshots_offset;
      # snapshot table 相对于镜像文件在存储中起始位置的偏移量, 需要与 cluster 对齐

  } QCowHeader;

NOTE 1: 上述所有的偏移量数值, 都是为了帮助 QCOW2 镜像文件定位相应的 metadata table.
NOTE 2: QCOW2 镜像文件格式的块设备数据都被储存在一个个 cluster 中, 而 QCOW2 Header 也是保存在一个 cluster 中
NOTE 3: L1 和 L2 tables 结合使用能够实现将磁盘镜像地址映射到镜像文件偏移
NOTE 4: 每一个 cluster 都有一个引用计数值, 当引用计数值为 0 时, 该 cluster 能够被删除

QCOW2 的 COW 特性

一个 QCOW2 镜像能够用于保存其它 QCOW2 镜像(模板镜像)的变化, 这样是为了能够保证原有镜像的内容不被修改, 这就是所谓的增量镜像. 增量镜像看着就像是一个独立的镜像文件, 其所有数据都是从模板镜像获取的. 仅当增量镜像中 clusters 的内容与模板镜像对应的 clusters 不一样时, 这些 clusters 才会被保存到增量镜像中.

当要从增量镜像中读取一个 cluster 时, QEMU 会先检查这个 cluster 在增量镜像中有没有被分配新的数据(被改变了). 如果没有, 则会去读模板镜像中的对应位置.

QCOW2 的快照

从原理的层面上来说, 一个增量镜像可以近似的当作一个快照, 因为增量镜像相对于模板镜像而言, 就是模板镜像的一个快照. 可以通过创建多个增量镜像来实现创建多个模板镜像的快照, 每一个快照(增量镜像)都引用同一个模板镜像. 需要注意的是, 因为模板镜像不能够修改, 所以必须保持为 read only, 而增量镜像则为可读写. 但需要注意的是增量镜像并不是真正的 QCOW2 镜像快照, 因为「真快照」是存在于一个镜像文件里的.

qemu-img 的基本使用

列举一些常用的 qemu-img 指令.

  • 创建 QCOW2 镜像文件: qemu-img create
# 指定容量为 4G
fanguiju@fanguiju:~$ qemu-img create -f qcow2 test.qcow2 4G
Formatting 'test.qcow2', fmt=qcow2 size=4294967296 encryption=off cluster_size=65536 lazy_refcounts=off
  • 查看 QCOW2 镜像文件信息: qemu-img info
fanguiju@fanguiju:~$ qemu-img info test.qcow2
image: test.qcow2
file format: qcow2
virtual size: 4.0G (4294967296 bytes)
disk size: 196K
cluster_size: 65536
Format specific information:
    compat: 1.1
    lazy refcounts: false
  • 创建 QCOW2 的快照: qemu-img snapshot
fanguiju@fanguiju:~$ qemu-img snapshot -c snap1 test.qcow2

# 再次查看 QCOW2 镜像文件信息, 可以看见 Snapshot list
fanguiju@fanguiju:~$ qemu-img info test.qcow2
image: test.qcow2
file format: qcow2
virtual size: 4.0G (4294967296 bytes)
disk size: 204K
cluster_size: 65536
Snapshot list:
ID        TAG                 VM SIZE                DATE       VM CLOCK
1         snap1                     0 2017-04-07 17:14:24   00:00:00.000
Format specific information:
    compat: 1.1
    lazy refcounts: false
  • 再次创建 QCOW2 的快照2:
fanguiju@fanguiju:~$ qemu-img snapshot -c snap2 test.qcow2

fanguiju@fanguiju:~$ qemu-img info test.qcow2
image: test.qcow2
file format: qcow2
virtual size: 4.0G (4294967296 bytes)
disk size: 212K
cluster_size: 65536
Snapshot list:
ID        TAG                 VM SIZE                DATE       VM CLOCK
1         snap1                     0 2017-04-07 17:14:24   00:00:00.000
2         snap2                     0 2017-04-07 17:17:54   00:00:00.000
Format specific information:
    compat: 1.1
    lazy refcounts: false
  • 删除 QCOW2 镜像文件的快照:
fanguiju@fanguiju:~$ qemu-img snapshot -d snap1 test.qcow2
fanguiju@fanguiju:~$ qemu-img info test.qcow2
image: test.qcow2
file format: qcow2
virtual size: 4.0G (4294967296 bytes)
disk size: 208K
cluster_size: 65536
Snapshot list:
ID        TAG                 VM SIZE                DATE       VM CLOCK
2         snap2                     0 2017-04-07 17:17:54   00:00:00.000
Format specific information:
    compat: 1.1
    lazy refcounts: false
  • 恢复 QCOW2 镜像文件的快照:
fanguiju@fanguiju:~$ qemu-img snapshot -a snap2 test.qcow2
  • 创建基于 QCOW2 镜像文件的镜像
    创建一个基于镜像 1(test.qcow2) 的镜像 2(test_1.qcow2), test.qcow2 成为了 test_1.qcow2 的 backing file. 对 test_1.qcow2 所作的 I/O 操作都不会影响到 test.qcow2. test.qcow2  仍能够作为其他镜像的 backing file. 前提是 test.qcow2 不被修改.
    NOTE: 如果作为 backing file 的镜像文件被修改了, 那么会影响到所有基于它的镜像文件.
fanguiju@fanguiju:~$ qemu-img create -b test.qcow2 -f qcow2 test_1.qcow2
Formatting 'test_1.qcow2', fmt=qcow2 size=4294967296 backing_file='test.qcow2' encryption=off cluster_size=65536 lazy_refcounts=off

# 可以看出镜像 test_1.qcow2 的 backing file 是 test.qcow2
fanguiju@fanguiju:~$ qemu-img info test_1.qcow2
image: test_1.qcow2
file format: qcow2
virtual size: 4.0G (4294967296 bytes)
disk size: 196K
cluster_size: 65536
backing file: test.qcow2
Format specific information:
    compat: 1.1
    lazy refcounts: false
  • * 让 QCOW2 镜像文件脱离 backing file*: qemu-img convert
    convert 用于转换镜像文件的格式, 当源镜像和目的镜像的格式均为 qcow2 时, 就相当于将源镜像的当前状态复制到目标镜像.
    同时也因为被转换出来的目的镜像不会包含任何源镜像的快照, 所以目的镜像能够摆脱 backing file.
# 将 test_1.qcow2 的状态复制到 test_1-merge.qcow2
fanguiju@fanguiju:~$ qemu-img convert -p -f qcow2 test_1.qcow2 -O qcow2 test_1-merge.qcow2
    (100.00/100%)

fanguiju@fanguiju:~$ qemu-img info test_1.qcow2
image: test_1.qcow2
file format: qcow2
virtual size: 4.0G (4294967296 bytes)
disk size: 196K
cluster_size: 65536
backing file: test.qcow2
Format specific information:
    compat: 1.1

fanguiju@fanguiju:~$ qemu-img info test_1-merge.qcow2
image: test_1-merge.qcow2
file format: qcow2
virtual size: 4.0G (4294967296 bytes)
disk size: 196K
cluster_size: 65536
Format specific information:
    compat: 1.1
    lazy refcounts: false
  • 更改 QCOW2 镜像文件的 backing file
fanguiju@fanguiju:~$ qemu-img create -f qcow2 base.qcow2 1G
Formatting 'base.qcow2', fmt=qcow2 size=1073741824 encryption=off cluster_size=65536 lazy_refcounts=off

fanguiju@fanguiju:~$ qemu-img info test_1.qcow2
image: test_1.qcow2
file format: qcow2
virtual size: 4.0G (4294967296 bytes)
disk size: 196K
cluster_size: 65536
backing file: test.qcow2
Format specific information:
    compat: 1.1
    lazy refcounts: false

fanguiju@fanguiju:~$ qemu-img rebase test_1.qcow2 -b base.qcow2

fanguiju@fanguiju:~$ qemu-img info test_1.qcow2
image: test_1.qcow2
file format: qcow2
virtual size: 4.0G (4294967296 bytes)
disk size: 196K
cluster_size: 65536
backing file: base.qcow2
Format specific information:
    compat: 1.1
    lazy refcounts: false
  • QCOW2 镜像文件转换成 RAW 格式:
fanguiju@fanguiju:~$ qemu-img convert test.qcow2 -O raw test.img

RAW 与 QCOW2 的区别

两者的区别之一就是是否具有稀疏(Sparse File)特性. (关于 Sparse File 和 holes 的详细介绍, 请查阅扩展阅读.)

RAW 支持 Sparse File, 其内部块中含有若干的 holes. 这些 holes 会被 HostOS Filesystems 管理. 如果我们创建了一个 RAW(20G) 镜像文件, 使用 ls 指令查看该文件大小为 20G, 但如果使用 du 指令来查看其大小时就会变得很小, 这是因为 RAW(20G) 文件中存在若干的 holes.  
EXAMPLE:

$> qemu-img info rhel6_0.img
image: rhel6_0.img
file format: raw
virtual size: 20G (21474836480 bytes)
disk size: 1.0G

$> ls -lh rhel6_0.img
-rw-r--r-- 1 root root 20G Apr  7 23:15 rhel6_0.img

$> du -h rhel6_0.img
1.1G    rhel6_0.img

相对的, 如果创建一个同为 20G 的 QCOW2 镜像文件, 无论是使用 ls 还是 du 指令查看到的文件 Size 都应该是一致的. 这说明 QCOW2 镜像文件除了含有作为一个块设备所需要的数据信息之外, 其自身还包含了内部块分配信息的记录.  
EXAMPLE:

$> qemu-img info rhel6_0
image: rhel6_0
file format: qcow2
virtual size: 20G (21474836480 bytes)
disk size: 1.0G
cluster_size: 262144
Format specific information:
    compat: 1.1
    lazy refcounts: false

$> ls -lh rhel6_0
-rw-r--r-- 1 root root 1.1G Apr  6 19:26 rhel6_0

$> du -h rhel6_0
1.1G    rhel6_0

需要注意的是: 虽然 Sparse File 特性会导致镜像文件的内部块中存在 holes, 但实际上 holes 是不会占用存储空间的, 无论是 RAW(Support Sparse File) 还是 QCOW2(Don’t Support Sparse Files), 两者的磁盘利用率相等, 因为物理硬盘的块数量是固定的, 不会受到 holes 的影响. 虽说 holes 不会影响最终的磁盘使用率, 不过 holes 能够引起某些应用进程的「误解」. 例如: 上面已经举例的 ls 指令, 除此之外, 在 scp RAW 镜像文件时, 会消耗更大的网络 I/O. 同样的, tar RAW 镜像文件时也会消耗更长的时间和 CPU. 这也算是 RAW 的一大缺点了, 一般的解决方法就是将 RAW 转换为 QCOW2 之后再进行压缩或传输.

当然, Sparse File 也是具有其优势的:
The advantage of sparse files is that storage is only allocated when actually needed: disk space is saved, and large files can be created even if there is insufficient free space on the file system.
Sparse FIle 的优势在于: 存储只有在实际需要时, 空间才会被分配. 存储的实际空间被保留了起来, 所以即使在文件系统上显示以及没有足够的可用空间时, 仍然可以创建大文件.

除了 Sparse File  特性的区别之外, 使用 RAW 启动的虚拟机会比 QCOW2 启动的虚拟机 I/O 效率更高一些(25%), 所以如果追求性能的话建议选用 RAW 格式.

                   $(function () {                 $('pre.prettyprint code').each(function () {                     var lines = $(this).text().split('\n').length;                     var $numbering = $('<ul/>').addClass('pre-numbering').hide();                     $(this).addClass('has-numbering').parent().append($numbering);                     for (i = 1; i <= lines; i++) {                         $numbering.append($('<li/>').text(i));                     };                     $numbering.fadeIn(1700);                 });             });        

相关文章
|
存储 Kubernetes 算法
开源免费的对象存储Minio
Minio是一个基于Apache License v2.0开源协议的对象存储服务。它兼容亚马逊S3云存储服务接口,非常适合存储大容量、非结构化的数据。例如,图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小的,从几KB到5TB不等。
2769 0
|
7月前
|
安全 物联网 API
Windows 11 25H2 | 24H2 中文版、英文版 (x64、ARM64) 下载 (2025 年 12 月更新)
Windows 11, version 25H2 Enterprise Arm64 x64 (updated Dec 2025)
605 0
Windows 11 25H2 | 24H2 中文版、英文版 (x64、ARM64) 下载 (2025 年 12 月更新)
|
人工智能 安全 编译器
华为自研仓颉编程语言将开源,未来与ArkTS同等地位
在2025年华为开发者大会上,华为正式推出HarmonyOS 6 Developer Beta,并宣布仓颉编程语言将于7月30日开源。作为定位下一代的编程语言,仓颉具备高效开发、安全可靠、轻松并发与卓越性能等特性,支持多范式编程与全面工具链,助力鸿蒙生态构建。
836 1
华为自研仓颉编程语言将开源,未来与ArkTS同等地位
|
存储 关系型数据库
ceph的存储池管理
本文介绍了Ceph存储池的管理,包括存储池的类型、PG数量的计算方法、创建和查看存储池、修改存储池信息以及删除存储池的操作步骤和注意事项。
993 2
|
数据采集 JSON 网络协议
Python编程异步爬虫——aiohttp的使用
Python编程异步爬虫——aiohttp的使用
911 0
|
机器学习/深度学习 人工智能 自然语言处理
AI 绘画Stable Diffusion 研究(七) 一文读懂 Stable Diffusion 工作原理(1)
AI 绘画Stable Diffusion 研究(七) 一文读懂 Stable Diffusion 工作原理
1389 0
|
数据安全/隐私保护 流计算 开发者
python知识点100篇系列(18)-解析m3u8文件的下载视频
【10月更文挑战第6天】m3u8是苹果公司推出的一种视频播放标准,采用UTF-8编码,主要用于记录视频的网络地址。HLS(Http Live Streaming)是苹果公司提出的一种基于HTTP的流媒体传输协议,通过m3u8索引文件按序访问ts文件,实现音视频播放。本文介绍了如何通过浏览器找到m3u8文件,解析m3u8文件获取ts文件地址,下载ts文件并解密(如有必要),最后使用ffmpeg合并ts文件为mp4文件。
2243 1
|
应用服务中间件 nginx 索引
7-16| *8 directory index of "E:\wwwroot/" is forbidden, client: 127.0.0.1, server: 192.168.1.240, re
7-16| *8 directory index of "E:\wwwroot/" is forbidden, client: 127.0.0.1, server: 192.168.1.240, re
|
存储 安全 网络协议
WebDAV
WebDAV【2月更文挑战第28天】
3397 1