以下内容主要介绍 KVM 中最常见的 RAW 和 QCOW2 镜像格式以及一些准备知识,分别说明并加以对比
准备知识
ls
和du
的区别
ls - list directory contents
du - estimate file space usage
通过man手册可以看出du
命令查看的是磁盘空间占有数,而ls
展示的是文件的一些相关属性。而在Linux
中,一个文件占用的磁盘大小和一个文件的大小在众多情况下并不相等,下面通过示例来更清晰的说明。
# 创建一个13k的文件
[root@suhw ~]# dd if=/dev/zero of=output count=1 bs=13k
1+0 records in
1+0 records out
13312 bytes (13 kB, 13 KiB) copied, 0.00014904 s, 89.3 MB/s
# 通过 ls 查看文件大小
[root@suhw ~]# ls -lh output
-rw-r--r-- 1 root root 13K Jun 28 02:34 output
# 查看文件所占用磁盘大小
[root@suhw ~]# du -h output
16K output
# 查看详细文件信息
[root@suhw ~]# stat -f output
File: "output"
ID: 8ff451b39f9a1bcf Namelen: 255 Type: ext2/ext3
Block size: 4096 Fundamental block size: 4096
...
在上面例子中,先创建了一个13k的文件,通过ls
查看文件大小为13k,而通过du
查看变成了16k,是因为占用空间取决于文件系统的块(block)
的大小,linux一般默认为4k(4096bytes)
。所以一个大小为1bytes
的文件,最小也要占用4k
,例子中13k的文件所占用的空间就是 13 / 4 = 3.25 个block,通常一个block
只能被一个文件系统占用,因为实际占用就是4 blocks
,就是16k。
创建指定大小的文件
在日常开发过程中可能会遇到需要快速创建指定大小文件的场景,其中可能就需要用到文件空洞等概念,常用的命令有以下三个。
truncate
用法
truncate 选项... 文件...
作用
将文件缩减或扩展至指定大小。如果指定文件超出指定大小则超出的数据将丢失。
如果指定文件小于指定大小则用0 补足。(同样形成文件空洞,不会真实文件对应得改变磁盘大小)
常用操作
-s, --size=大小
。size后的数字若不指定单位则默认为字节数,也可指定KB/MB...
等单位。
指定大小也可使用以下前缀修饰:
- “+” 增加,"-" 减少,"<" 至多,">" 至少,
- “/” 小于等于原尺寸数字的指定数字的最小倍数,"%" 大于等于原尺寸数字的指定数字的最大倍数。
示例:
[root@suhw ~]# ls -lh test
-rw-r--r-- 1 root root 29 Jun 28 09:56 test
[root@suhw ~]# du -h test
4.0K test
[root@suhw ~]# truncate -s 2M test
[root@suhw ~]# ls -lh test
-rw-r--r-- 1 root root 2.0M Jun 28 10:00 test
[root@suhw ~]# du -h test
4.0K test
dd
作用
dd命令用于读取、转换并输出数据。
详细得用法可自行搜索,以下只介绍关于创建大文件相关的部分
常用参数
参数 | 作用 |
if=file | 输入文件名,缺省为标准输入。 从file读取,如if=/dev/zero |
of=file | 输出文件名,缺省为标准输出。 向file写出,可以写文件,可以写裸设备。如of=/dev/null |
ibs=bytes | 一次读入 bytes 个字节(即一个块大小为 bytes 个字节) |
obs=bytes | 一次写 bytes 个字节(即一个块大小为 bytes 个字节) |
bs=bytes | 同时设置读写块的大小为 bytes |
seek=blocks | 从输出文件开头跳过 blocks 个块后再开始复制 |
count=blocks | 仅拷贝 blocks 个块,块大小等于 ibs 指定的字节数 |
示例
1、不进行偏移,真实占用磁盘空间
下述命令相当于从/dev/zero
中拷贝一个块大小为1G
的数据到dd_test
文件中
[root@suhw ~]# dd if=/dev/zero of=dd_test count=1 bs=1G
1+0 records in
1+0 records out
1073741824 bytes (1.1 GB) copied, 5.67934 s, 189 MB/s
[root@suhw ~]# ls -lh dd_test
-rw-r--r-- 1 root root 1.0G Jun 28 11:07 dd_test
[root@suhw ~]# du -h dd_test
1.1G dd_test
2、使用文件偏移,形成文件空洞
若使用seek进行文件偏移,则就会形成文件空洞。
下述命令相当于从/dev/zero
中拷贝一个块大小为4M
的数据到dd_test
文件中,但先需要跳过输出文件开头的1000个大小为4M
的块。所以只拷贝了1*4M
个字节大小的内容到dd_seek
中(1*4*1024*1024=4194304 bytes),但是由于偏移了1000*4M个字节,导致 ls-lh
查看变成了4G
[root@suhw ~]# dd if=/dev/zero of=dd_seek count=1 bs=4M seek=1000
1+0 records in
1+0 records out
4194304 bytes (4.2 MB) copied, 0.0115562 s, 363 MB/s
[root@suhw ~]# ls -lh dd_seek
-rw-r--r-- 1 root root 4.0G Jun 28 11:09 dd_seek
[root@suhw ~]# du -h dd_seek
4.0M dd_seek
注:使用dd对磁盘操作时,最好使用块设备文件。
fallocate
fallocate命令可以为文件预分配物理空间。-l
后接空间大小,默认单位为字节。也可后跟k、m、g、t、p、e来指定单位,分别代表KB、MB、GB、TB、PB、EB。
[root@suhw ~]# fallocate -l 1G test_file
[root@csmp-standalone ~]# ll
-rw-r--r-- 1 root root 1073741824 Jun 24 21:41 test_file
# 查看文件占用磁盘大小
[root@csmp-standalone ~]# du -h test_file
1.1G test_file
文件空洞
在UNIX
文件操作中,文件偏移量可以大于文件的当前长度,在这种情况下,对该文件的下一次写将延长该文件,并在文件中构成一个空洞,从而形成空洞文件,位于文件中但没有写过的字节都被设为 0。
文件空洞的表现
空洞文件在文件系统上表现的还是和普通文件相同,但是实际上文件系统并没有为空洞文件分配与逻辑大小相同的磁盘空间大小
# 创建一个4M大小得空洞文件
[root@suhw ~]# dd if=/dev/zero of=test bs=1 count=0 seek=4M
0+0 records in
0+0 records out
0 bytes (0 B) copied, 0.000332336 s, 0.0 kB/s
# 查看文件大小
[root@suhw ~]# ls -lh test
-rw-r--r-- 1 root root 4.0M Jun 24 17:23 test
#查看占用磁盘大小
[root@suhw ~]# du -h test
0 test
文件空洞作用
- 迅雷下载文件时,在未下载完成时就已经占据了全部文件大小的空间,这时候就是空洞文件。下载的时候如果没有空洞文件,多线程下载时文件就都只能从一个地方写入,此时就会出问题。如果有了空洞文件,可以从不同的地址写入,就完成了多线程的优势任务。
- 在创建虚拟机的时候,我们会使用img工具生成一个例如50GB大小的镜像文件,但是其实在安装完系统之后,镜像的大小可能只有4GB,也就是说img并不会马上就占用掉物理存储空间的50GB,而是在未来使用过程中不断增加的。
稀疏文件
稀疏文件,这是UNIX类和NTFS等文件系统的一个特性。稀疏文件就是在文件中留有很多空余空间,留备将来插入数据使用。如果这些空余空间被ASCII码的NULL字符占据,并且这些空间相当大,那么,这个文件就被称为稀疏文件,而且,这些多余得空间并不分配对应的磁盘块。可以参考下图了解
优势
它分配的存储空间只在需要时使用,这样节省了磁盘空间,并且可以创建很大的文件,即使文件系统中的可用空间不足。这也减少了首次写入的时间,因为系统不会分配“跳过”的空间。如果初始分配需要写入全零到空间,这也使得系统不必写入两次。
镜像格式
kvm虚拟机中需要选择磁盘镜像的格式,通常的选择就是RAW
格式和QCOW2
格式。
qcow2
介绍
QCOW2(qemu copy on write 2)
格式包含一些特性,包括支持多重快照,占用更小的存储空间(不支持稀疏特性,也就是不会预先分配指定 size 的空间),可选的 AES 加密和可选的 zlib 压缩方式。
qcow2是kvm支持的磁盘镜像格式,我们创建一个100G的qcow2磁盘之后,无论用ls来看,还是du来看,都是很小的。这说明了,qcow2本身会记录一些内部块分配的信息的。
特性
与普通的 raw 格式的镜像相比,有以下特性:
- 更小的空间占用,即使文件系统不支持空洞(holes);
- 支持写时拷贝(COW, copy-on-write),镜像文件只反映底层磁盘的变化;
- 支持快照(snapshot),镜像文件能够包含多个快照的历史;
- 可选择基于 zlib 的压缩方式
- 可以选择 AES 加密
raw
RAW 的原意是「未被加工的」, 所以 RAW 格式镜像文件又被称为 原始镜像 或 裸设备镜像, 从这些称谓可以看出, RAW 格式镜像文件能够直接当作一个块设备, 以供 GuestOS 使用. 也就是说 KVM 的 GuestOS 可以直接从 RAW 镜像中启动, 就如 HostOS 直接从硬盘中启动一般。至于文件里面的空洞,则是由宿主机的文件系统来管理的,linux下的文件系统可以很好的支持空洞的特性,所以,如果你创建了一个100G的raw格式的文件,ls看的时候,可以看到这个文件是100G的,但是用du 来看,这个文件会很小。
优点
- 使用 dd 指令创建一个 File 就能够模拟 RAW 镜像文件
- 性能较 QCOW2 要更高
- 支持裸设备的原生特性, 例如: 直接挂载
- 能够随意转换格式, 甚至作为其他两种格式转换时的中间格式
- 能够使用 dd 指令来追加 RAW 镜像文件的空间
缺点
- 由于支持文件空洞,所以
ls
查看时文件很大,在scp
传输时会消耗很多网络io
。所以传输时可通过qemu-img convert
转为qcow2
再进行传输
占用空间示例
首先分别创建大小为10G的 raw 和 qcow2格式的镜像
[root@suhw ~]# qemu-img create -f qcow2 qcow2-image.qcow2 2G
Formatting 'qcow2-image.qcow2', fmt=qcow2 size=2147483648 cluster_size=65536 lazy_refcounts=off refcount_bits=16
[root@suhw ~]# qemu-img create -f raw raw-image.raw 2G
Formatting 'qcow2-image.raw', fmt=raw size=2147483648
对比两个镜像文件发现,raw
格式的文件没有占用磁盘文件(空洞文件),qcow2的文件占用约200k,同时占用了约400块block
[root@suhw ~]# ls -lh *-image*
-rw-r--r-- 1 root root 193K Jun 28 02:14 qcow2-image.qcow2
-rw-r--r-- 1 root root 2.0G Jun 28 02:14 raw-image.raw
[root@suhw ~]# du -h *-image*
196K qcow2-image.qcow2
0 raw-image.raw
[root@suhw ~]# stat qcow2-image.qcow2
File: 'qcow2-image.qcow2'
Size: 196640 Blocks: 392 IO Block: 4096 regular file
...
[root@suhw ~]# stat raw-image.raw
File: 'raw-image.raw'
Size: 2147483648 Blocks: 0 IO Block: 4096 regular file
...
镜像格式转换
QEMU
中提供的 qemu-img
工具可用于镜像的一些常用操作,其中就包含镜像格式的转换。
转换的命令如下:
qemu-img convert -f qcow2 -O raw /tmp/test.qcow2 /tmp/test.raw -p
参数介绍
-
-p
显示转换过程 -
-f
原始格式 -
-O
要输出的格式
raw
转 qcow2
也同理,只需要更换参数顺序和文件
qemu-img convert -f raw -O qcow2 centos.raw centos.qcow2
参考
- https://yq.aliyun.com/articles/237275
- https://www.aikaiyuan.com/8277.html
- https://banbanpeppa.github.io/2019/08/21/linux/holefile/