共計 6677 個字符,預(yù)計需要花費 17 分鐘才能閱讀完成。
本篇內(nèi)容主要講解“Linux 中 sparse 文件處理與傳輸?shù)姆椒ㄊ鞘裁础保信d趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強(qiáng)。下面就讓丸趣 TV 小編來帶大家學(xué)習(xí)“Linux 中 sparse 文件處理與傳輸?shù)姆椒ㄊ鞘裁础卑?
0. 什么是 sparse 文件
當(dāng)用戶申請一塊很大的存儲空間時,由于最開始并沒有寫入數(shù)據(jù)(全是空),此時文件系統(tǒng)為了節(jié)省存儲資源,提高資源利用率,不會分配實際存儲空間,只有當(dāng)真正寫入數(shù)據(jù)時,操作系統(tǒng)才真正一點一點地分配空間,比如一次 64KB。于是這個文件看起來很大,而占用空間很小,實際占用空間只與用戶填的數(shù)據(jù)量有關(guān)。該文件看起來像一個大盒子,但可能裝的東西不多,空洞很大,因此稱為稀疏文件(Sparse file)。Sparse 文件是 Linux 文件系統(tǒng)的一個高級特性,能夠?qū)崿F(xiàn)磁盤的超負(fù)載使用(overload)。它最經(jīng)典的應(yīng)用就是為虛擬機(jī)創(chuàng)建虛擬硬盤以及數(shù)據(jù)庫快照,比如我們使用 qemu-img 創(chuàng)建一個大小為 20GB 的 raw 文件(注意 qcow2 格式不是 sparse 文件):
fgp@node1:~$ qemu-img create -f raw test.raw 20G Formatting test.raw , fmt=raw size=21474836480 fgp@node1:~$ qemu-img info test.raw image: test.raw file format: raw virtual size: 20G (21474836480 bytes) disk size: 0
以上我們使用 qemu-img 創(chuàng)建了一個 20G 的鏡像文件,由 qemu-img info 顯示,virtual size 為我們分配的空間大小,而 disk size 為實際占用的空間, 最開始并不占任何磁盤空間。
注:qemu-img create -f raw 相當(dāng)于 `truncate -s 20G test.raw rsquo;。
當(dāng)然也會有問題,比如系統(tǒng)生成了一堆 sparse 文件,如果文件系統(tǒng)滿了,則這些文件都會寫入失敗,為了避免這種情況,需要控制 sparse 文件的數(shù)量。
1. 如何判斷是否 sparse 文件
除了以上的鏡像文件可能是 sparse 文件,其他文件類型也有可能是 sparse 文件,如何判斷是否 sparse 文件呢? 最簡單的辦法是使用 ls 命令和 du 命令分別查看大小,如果二者大小不一致,則說明是 sparse 文件。我們可以使用 dd 命令快速生成一個 sparse 文件:
dd if=/dev/zero of=sparse_file bs=1M seek=1024 count=0
以上命令從第 1024 * 1M 處開始寫文件(相當(dāng)于中間空了 1GB 空間),寫入 /dev/zero,實際寫入了 0 個塊(count=0),因此實際上并沒有寫入任何數(shù)據(jù)。我們使用 ls -lh 查看其大小:
~$ ls -lh sparse_file -rw-rw-r-- 1 fgp fgp 1.0G May 26 15:47 sparse_file
可見該文件顯示為 1G。
我們再使用 du - h 命令查看其占用磁盤空間大小:
~$ du -h sparse_file 0 sparse_file
我們發(fā)現(xiàn)實際占用磁盤空間為 0。
我們也可以直接使用 ls 的 - s 參數(shù)查看文件實際占用空間大小:
~$ ls -slh sparse_file 0 -rw-rw-r-- 1 fgp fgp 1.0G May 26 15:47 sparse_file
其中 *** 列為實際占用磁盤空間大小,第 6 列為文件大小(虛擬大小)。
另外使用 truncate 命令可以隨意調(diào)節(jié)文件大小(如果該文件不存在則會自動創(chuàng)建),比如:
~$ truncate --size 1T sparse_file ~$ du -h sparse_file 0 sparse_file
~$ ls -lh sparse_file -rw-rw-r-- 1 fgp fgp 1.0T May 26 16:09 sparse_file
以上我們把 sparse_file 文件大小調(diào)為 1TB,實際上就是往后面追加空洞(extended part (hole) reads as zero bytes), 因此不會占用實際磁盤空間。當(dāng)然也可以縮小文件大小,但是如果比文件數(shù)據(jù)占用空間還小的話,就會截取數(shù)據(jù),因此部分?jǐn)?shù)據(jù)會丟失。
truncate -s 500M sparse_file ~$ ls -lh sparse_file -rw-rw-r-- 1 fgp fgp 500M May 26 16:12 sparse_file
以上我們把該文件縮減為 500MB。
2. sparse 文件處理
sparse 文件在處理時也存在一些問題,比如我們使用 sed 對一個 sparse 文件進(jìn)行處理。
fgp@node1:~/tmp$ echo Hello World test.raw fgp@node1:~/tmp$ truncate -s 1G test.raw fgp@node1:~/tmp$ ls -slh total 68K 4.0K -rw-rw-r-- 1 fgp fgp 1.0G May 28 14:52 test.raw fgp@node1:~/tmp$ sed -i s/Hello/HELLO/g test.raw fgp@node1:~/tmp$ ls -slh total 1.1G 1.1G -rw-rw-r-- 1 fgp fgp 1.0G May 28 14:53 test.raw
以上我們使用 truncate 創(chuàng)建了一個 sparse 文件,然后通過 sed 命令把 Hello 改為 HELLO,我們期望能夠保留該文件的 sparse 特性,但實際上我們發(fā)現(xiàn)僅僅修改了該文件的一行數(shù)據(jù),該文件的空洞被填滿,瞬間占用磁盤空間為 1G。一個只有 4K 大小的文件使用 sed 命令后變成了 1G,這讓人感到莫名其妙不是嗎?
再比如我們我們使用 tar 命令對文件進(jìn)行歸檔:
fgp@node1:~/tmp$ qemu-img create -f raw test.raw 1G Formatting test.raw , fmt=raw size=1073741824 fgp@node1:~/tmp$ time tar -cf test.tar test.raw real 0m2.145s user 0m0.012s sys 0m1.640s fgp@node1:~/tmp$ time tar -cJf test.tar.xz test.raw real 1m0.692s user 0m59.060s sys 0m1.048s fgp@node1:~/tmp$ ls -lsh total 1.1G 0 -rw-r--r-- 1 fgp fgp 1.0G May 28 15:37 test.raw 1.1G -rw-rw-r-- 1 fgp fgp 1.1G May 28 15:37 test.tar 156K -rw-rw-r-- 1 fgp fgp 153K May 28 15:39 test.tar.xz
以上我們創(chuàng)建了一個 1G 的 sparse 文件,當(dāng)使用 tar 直接歸檔時發(fā)現(xiàn)該文件變成了非 sparse 文件,占用了 1G 的磁盤空間。而使用 xz 壓縮時,雖然解決了存儲空間的問題,同時也帶來壓縮時間開銷問題(耗費了 1 分鐘的時間進(jìn)行壓縮)。
接下來介紹下熟悉的經(jīng)典命令 cp,cp 命令可謂無人不知。眾所周知,它用于在本地拷貝文件。值得慶幸 (為什么慶幸,因為并不是所有的命令都支持該特性) 的是 cp 命令能夠自動探測文件是否 sparse 文件,空洞數(shù)據(jù)不會拷貝,并且能夠保留 sparce 文件副本的稀疏性質(zhì):
fgp@node1:~$ cp sparse_file sparse_file.copy fgp@node1:~$ ls -slh sparse_file* 0 -rw-rw-r-- 1 fgp fgp 2.0G May 26 16:39 sparse_file 0 -rw-rw-r-- 1 fgp fgp 2.0G May 26 16:39 sparse_file.copy
我們看看和 cp 命令類似的命令 scp,scp 用于遠(yuǎn)程拷貝文件(遠(yuǎn)程傳輸文件):
fgp@node1:~$ scp sparse_file localhost:~/sparse_file.copy sparse_file 100% 2048MB 97.5MB/s 00:21 fgp@node1:~$ ls -slh sparse_file* 0 -rw-rw-r-- 1 fgp fgp 2.0G May 26 16:39 sparse_file 2.1G -rw-rw-r-- 1 fgp fgp 2.0G May 26 16:42 sparse_file.copy
我們發(fā)現(xiàn) scp 不能識別 sparse 文件,傳輸一個 sparse 文件時會自動填滿空洞,發(fā)送整個文件內(nèi)容。
其實 cp 命令有一個針對 sparse 文件拷貝優(yōu)化的參數(shù) –sparse=WHEN,其中 WHEN 的合法值為 auto、always、never,默認(rèn)為 auto,能自動識別是否 sparse 文件。如果設(shè)置為 never 則會自動填滿數(shù)據(jù),拷貝整個文件:
fgp@node1:~$ cp --sparse=never sparse_file sparse_file.copy.2 fgp@node1:~$ ls -lhs sparse_file* 0 -rw-rw-r-- 1 fgp fgp 2.0G May 26 16:39 sparse_file 2.1G -rw-rw-r-- 1 fgp fgp 2.0G May 26 16:42 sparse_file.copy 2.1G -rw-rw-r-- 1 fgp fgp 2.0G May 26 16:50 sparse_file.copy.2
可見 sparse_file.copy.2 填滿了空洞,相當(dāng)于把 sparse 文件轉(zhuǎn)化成了非 sparse 文件。
如果指定為 always,則 cp 會嘗試把文件轉(zhuǎn)換為 sparse 文件,減少磁盤占用空間:
fgp@node1:~$ cp --sparse=always sparse_file.copy sparse_file.copy.3 fgp@node1:~$ ls -lsh sparse_file* 0 -rw-rw-r-- 1 fgp fgp 2.0G May 26 16:39 sparse_file 2.1G -rw-rw-r-- 1 fgp fgp 2.0G May 26 16:42 sparse_file.copy 2.1G -rw-rw-r-- 1 fgp fgp 2.0G May 26 16:50 sparse_file.copy.2 0 -rw-rw-r-- 1 fgp fgp 2.0G May 26 16:52 sparse_file.copy.3
由結(jié)果發(fā)現(xiàn),我們把非 sparse 文件 sparse_file.copy 轉(zhuǎn)成了 sparse 文件 sparse_file.copy.3。
注:cp 命令黑科技,cp 實現(xiàn) sparse 文件的相互轉(zhuǎn)換!
其實除了 cp 命令,我們上面的 tar 命令也支持 ndash;sparse 參數(shù):
fgp@node1:~/tmp$ time tar -cSf test.tar test.raw real 0m0.002s user 0m0.000s sys 0m0.000s fgp@node1:~/tmp$ time tar -cSJf test.tar.xz test.raw real 0m0.011s user 0m0.000s sys 0m0.008s fgp@node1:~/tmp$ ls -slh total 16K 0 -rw-r--r-- 1 fgp fgp 1.0G May 28 15:37 test.raw 12K -rw-rw-r-- 1 fgp fgp 10K May 28 15:42 test.tar 4.0K -rw-rw-r-- 1 fgp fgp 184 May 28 15:43 test.tar.xz
對比前面的結(jié)果,我們發(fā)現(xiàn)使用 tar 的 -S(ndash;sparse)參數(shù)很好的處理 sparse 文件。
另外 cpio 也支持同樣的參數(shù),但可惜的是 scp 命令不支持,因此我們使用 scp 遠(yuǎn)程傳輸大量的 sparse 文件時效率極低,并且浪費大量網(wǎng)絡(luò)空間。比如我們經(jīng)常使用 qemu-img 創(chuàng)建了一個 40GB 的 raw 文件,然后需要拷貝鏡像到其他機(jī)器上,雖然該文件可能只占了 1GB 左右的磁盤空間,可使用 scp 需要傳輸 40GB 的空間,并且遠(yuǎn)程需要預(yù)留 40GB 的磁盤空間。那有沒有高效傳輸 sparse 文件的方法呢? 實際上,很可惜,好像并沒有,不過有比較好的方法,請看下一節(jié)內(nèi)容。
3. 相對高效傳輸 sparse 文件的方法
我們前面說了 scp 不支持 sparse 文件的處理,好在 rsync 命令支持 sparse 文件處理:
fgp@node1:~$ rsync -av --sparse --progress sparse_file localhost:~/sparse_file.copy fgp@localhost s password: sending incremental file list sparse_file 2,147,483,648 100% 74.67MB/s 0:00:27 (xfr#1, to-chk=0/1) sent 2,148,008,037 bytes received 35 bytes 66,092,556.06 bytes/sec total size is 2,147,483,648 speedup is 1.00 fgp@node1:~$ ls -lhs sparse_file* 0 -rw-rw-r-- 1 fgp fgp 2.0G May 26 16:39 sparse_file 0 -rw-rw-r-- 1 fgp fgp 2.0G May 26 16:39 sparse_file.copy
遺憾的是,雖然目標(biāo)文件保留了其 sparse 特性,節(jié)省了目標(biāo)主機(jī)的存儲空間,但并沒有節(jié)省網(wǎng)絡(luò)傳輸帶寬,依然傳輸了 2GB 的數(shù)據(jù),rsync 不能過濾掉空洞數(shù)據(jù)的傳輸。
值得一提的是 rsync 有一個參數(shù) –inplace,這個參數(shù)能夠探測源文件和目標(biāo)文件是否修改的塊,傳輸時只傳遞修改的塊,當(dāng)然 *** 次傳輸文件時,這個參數(shù)并沒有什么用。但可惜的是 ndash;sparse 參數(shù)和 ndash;inplace 參數(shù)不能同時使用。通常做法是 *** 次傳輸文件時,使用 ndash;sparse 參數(shù),之后如果對文件進(jìn)行了修改,需要同步遠(yuǎn)程時,使用 ndash;inplace 參數(shù),它只會在原文件的基礎(chǔ)上傳輸更新的塊。(可以先在遠(yuǎn)程目標(biāo)機(jī)器上先使用 truncate 命令創(chuàng)建一個同名的 sparse 文件,再使用 ndash;inplace 參數(shù)傳遞)。
當(dāng)然如果我們傳輸?shù)氖晴R像文件,可以通過 qemu-img 把 raw 格式在本地轉(zhuǎn)化為 qcow2 格式后再傳輸:
fgp@node1:~/tmp$ ls -lsh total 0 0 -rw-rw-r-- 1 fgp fgp 10G May 28 15:00 test.raw fgp@node1:~/tmp$ qemu-img convert -f raw -O qcow2 test.raw test.qcow2 fgp@node1:~/tmp$ ls -lsh total 196K 196K -rw-r--r-- 1 fgp fgp 193K May 28 15:12 test.qcow2 0 -rw-rw-r-- 1 fgp fgp 10G May 28 15:00 test.raw
轉(zhuǎn)化成 qcow2 格式后,不再是 sparse 文件,因此不會存在以上問題。由以上輸出我們發(fā)現(xiàn),該文件只有 196K,因此傳輸量大幅度減少。
到此,相信大家對“Linux 中 sparse 文件處理與傳輸?shù)姆椒ㄊ鞘裁础庇辛烁畹牧私猓环羴韺嶋H操作一番吧!這里是丸趣 TV 網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!