以下內容主要介紹 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/