本文介紹了 qcow2 和 raw,它們都是 QEMU(KVM)虛擬機使用的磁盤文件格式,本文將從其實現原理,支持特性,以及讀寫效率等進行對比和分析,最後還要介紹這兩種格式的磁盤文件如何轉化。
qcow2 鏡像格式是 QEMU 模擬器支持的一種磁盤鏡像。它也是可以用一個文件的形式來表示一塊固定大小的塊設備磁盤。與普通的 raw 格式的鏡像相比,有以下特性:
每一個 qcow2 文件都以一個大端(big-endian)格式的頭開始,結構如下:
typedef struct QCowHeader { uint32_t magic; uint32_t version; uint64_t backing_file_offset; uint32_t backing_file_size; uint32_t cluster_bits; uint64_t size; /* in bytes */ uint32_t crypt_method; uint32_t l1_size; uint64_t l1_table_offset; uint64_t refcount_table_offset; uint32_t refcount_table_clusters; uint32_t nb_snapshots; uint64_t snapshots_offset; } QcowHeader;
下面以一個 10G 的 qcow2 文件為例來分析各字段的含義。
# file 1.cow2 1.cow2: QEMU QCOW Image (v2), 10737418240 bytes 0000000: 5146 49fb 0000 0002 0000 0000 0000 0000 QFI............. 0000010: 0000 0000 0000 0010 0000 0002 8000 0000 ................ 0000020: 0000 0000 0000 0014 0000 0000 0003 0000 ................ 0000030: 0000 0000 0001 0000 0000 0001 0000 0000 ................ 0000040: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0000050: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 0000060: 0000 0004 0000 0068 0000 0000 0000 0000 .......h........ 0000070: 0000 0000 0000 0000 0000 0000 0000 0000 ................ ......
前 4 個比特包含了字符 Q,F,I,然後是 0xfb,實例中的 5146 49fb 是 magic 字段。
接下來的 4 個比特包含了該鏡像文件的版本號,實例中的 0000 0002 是 version 字段,代表使用的是 qcow2 版本。
backing_file_offset 占用 8 個字節,實例中 0000 0000 0000 0000,給出一個從某個文件開始偏移量。
backing_file_size 給出了一個不以 null 結尾的字符串的長度,實例中為 0000 0000。如果這個鏡像文件是一個寫時拷貝的,那麼它是原始文件的路徑。
cluster_bits,32 位(0000 0010),描述了如何映射一個鏡像的地址到一個本地文件,它決定了在一個 cluster 中,偏移地址的低位是如何作為索引的。因為 L2 表占用了一個單獨的 cluster 並且包含 8 字節的表項(entry),所以 cluster_bits 只有不足 3 個位,作為 L2 表的索引。
接下來的 size ,8 字節代表了該鏡像文件所表示的塊設備的大小,實例中為 0000 0002 8000 0000 字節,也就是 10G 的空間。
crypt_method 如果為 1 代表使用 AES 加密。
l1_size(0000 0014)和 l1_table_offset(0000 0000 0003 0000::)分別給出了 L1 表大小和偏移量。
refcount_table_offset 給出 refcount 表的偏移量(0000 0000 0001 0000)而 refcount_table_clusters 描述了以 cluster 為單位的 refcount 表的大小(0000 0001)。
nb_snapshots 給出了該鏡像包含的快照數量(0000 0000), snapshots_offset 給出每個快照到 QCowSnapshotHeader 的偏移量(0000 0000 0000 0000)。
一個典型的 qcow2 鏡像文件包含一下幾部分:
在 qcow2 中,磁盤的內容是保存在 cluster 中(每個 cluster 包含一些大小為 512 字節的扇區)。為了找到給定地址所在的 cluster,我們需要查找兩張表,L1->L2。L1 表保存一組到 L2 表的偏移量,L2 表保存一組到 cluster 的偏移量;
所以一個地址要根據 cluster_bits(64 位)的設置分成 3 部分,比如說 cluster_bits=12;
低 12 位是一個 4Kb cluster 的偏移(2 的 12 次方=4Kb);
接下來 9 位是包含 512 個表項目的 L2 表;
剩下 43 位的代表 L1 表偏移量。
為了獲取一個給定地址(64 位)的偏移位置:
如果 L1 表和 L2 表中的偏移量都是空,這塊區域就尚未被鏡像文件分配。
注意 L1 表和 L2 表中的偏移量的前兩位被保留,用做表示'copied' 或'compressed'。
qcow2 鏡像可以用來保存另一個鏡像文件的變化,它並不去修改原始鏡像文件,只記錄與原始鏡像文件的不同即可,這種鏡像文件就叫做 copy-on-write 鏡像。雖然是一個單獨的文件,但它的大部分的數據都來自原始鏡像,只有跟原始鏡像文件相比有變化的 cluster 才會被記錄下來。
這很容易去實現,在頭部信息中記錄原始文件路徑即可。當需要從一個 copy-on-write 鏡像文件中讀取一個 cluster 的時候,首先檢查這塊區域是否已經在該鏡像文件中被分配,如果沒有就從原始文件讀取。
快照有些類似 Copy-On-Write 文件,但區別是快照是一個可寫的。快照就是原始文件本身(內部快照)。它既包含做快照之前的原始文件部分,它本身也包含可寫的部分。
每一個快照都包含如下的頭部結構:
清單 3. qcow2 快照 Header
typedef struct QCowSnapshotHeader { /* header is 8 byte aligned */ uint64_t l1_table_offset; uint32_t l1_size; uint16_t id_str_size; uint16_t name_size; uint32_t date_sec; uint32_t date_nsec; uint64_t vm_clock_nsec; uint32_t vm_state_size; uint32_t extra_data_size; /* for extension */ /* extra data follows */ /* id_str follows */ /* name follows */ } QcowSnapshotHeader;
qcow2 支持壓縮,它允許每個簇(cluster)單獨使用 zlib 壓縮。它也支持使用 128 位的 AES 密鑰進行加密。
使用 QEMU 軟件包自帶的 qemu-img 軟件創建 qcow2 文件。
$ qemu-img create -f qcow2 test.qcow2 10G Formatting 'test.qcow2', fmt=qcow2 size=10737418240 encryption=off cluster_size=65536 lazy_refcounts=off $ qemu-img create -f raw test.raw 10G Formatting 'test.raw', fmt=raw size=10737418240
對比兩種格式的文件的實際大小以及占用空間大小如下:
$ ll -sh test.* 200K -rw-r--r-- 1 qiaoliyong qiaoliyong 193K 5 月 6 10:29 test.qcow2 0 -rw-r--r-- 1 qiaoliyong qiaoliyong 10G 5 月 6 10:28 test.raw [qiaoliyong@localhost ]$ stat test.raw 文件:"test.raw" 大小:10737418240 塊:0 IO 塊:4096 普通文件 [qiaoliyong@localhost ]$ stat test.qcow2 文件:"test.qcow2" 大小:197120 塊:400 IO 塊:4096 普通文件
從對比中可以看出 qcow 格式的鏡像文件大小位 197120 字節,占用空間為 200K,占用了 200 塊磁盤空間。而 raw 格式的文件則沒有占用磁盤空間,它是一個空洞文件。
QEMU 軟件包裡面提供的 qemu-img 工具可用於 image 鏡像一些常用操作。
將 raw 格式轉化為 qcow2 格式的文件命令如下:
qemu-img convert -f raw -O qcow2 test.raw test.raw.qcow2 [qiaoliyong@localhost kimchi]$ ll -sh test.* 200K -rw-r--r-- 1 qiaoliyong qiaoliyong 193K 5 月 6 10:29 test.qcow2 0 -rw-r--r-- 1 qiaoliyong qiaoliyong 10G 5 月 6 10:28 test.raw 200K -rw-r--r-- 1 qiaoliyong qiaoliyong 193K 5 月 6 10:44 test.raw.qcow2
兩種格式文件的性能比較
表 1. 使用 ide 作為虛擬磁盤的驅動的三種鏡像格式性能對比
表 2. 使用 virtio 作為虛擬磁盤的驅動的三種鏡像格式性能對比
本文著重介紹了 QEMU 虛擬機使用的鏡像文件 qcow2 的格式以及特性,並與 raw 格式鏡像做了對比。qcow2 格式的文件雖然在性能上比rRaw 格式的有一些損失(主要體現在對於文件增量上,qcow2 格式的文件為了分配 cluster 多花費了一些時間),但是 qcow2 格式的鏡像比 Raw 格式文件更小,只有在虛擬機實際占用了磁盤空間時,其文件才會增長,能方便的減少遷移花費的流量,更適用於雲計算系統,同時,它還具有加密,壓縮,以及快照等 raw 格式不具有的功能。
Ubuntu 12.04之找不到Qemu命令 http://www.linuxidc.com/Linux/2012-11/73419.htm
Arch Linux上安裝QEMU+EFI BIOS http://www.linuxidc.com/Linux/2013-02/79560.htm
QEMU的翻譯框架及調試工具 http://www.linuxidc.com/Linux/2012-09/71211.htm
QEMU 的詳細介紹:請點這裡
QEMU 的下載地址:請點這裡