共计 6677 个字符,预计需要花费 17 分钟才能阅读完成。
本篇内容主要讲解“Linux 中 sparse 文件处理与传输的方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让丸趣 TV 小编来带大家学习“Linux 中 sparse 文件处理与传输的方法是什么”吧!
0. 什么是 sparse 文件
当用户申请一块很大的存储空间时,由于最开始并没有写入数据(全是空),此时文件系统为了节省存储资源,提高资源利用率,不会分配实际存储空间,只有当真正写入数据时,操作系统才真正一点一点地分配空间,比如一次 64KB。于是这个文件看起来很大,而占用空间很小,实际占用空间只与用户填的数据量有关。该文件看起来像一个大盒子,但可能装的东西不多,空洞很大,因此称为稀疏文件(Sparse file)。Sparse 文件是 Linux 文件系统的一个高级特性,能够实现磁盘的超负载使用(overload)。它最经典的应用就是为虚拟机创建虚拟硬盘以及数据库快照,比如我们使用 qemu-img 创建一个大小为 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 创建了一个 20G 的镜像文件,由 qemu-img info 显示,virtual size 为我们分配的空间大小,而 disk size 为实际占用的空间, 最开始并不占任何磁盘空间。
注:qemu-img create -f raw 相当于 `truncate -s 20G test.raw rsquo;。
当然也会有问题,比如系统生成了一堆 sparse 文件,如果文件系统满了,则这些文件都会写入失败,为了避免这种情况,需要控制 sparse 文件的数量。
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 处开始写文件(相当于中间空了 1GB 空间),写入 /dev/zero,实际写入了 0 个块(count=0),因此实际上并没有写入任何数据。我们使用 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
我们发现实际占用磁盘空间为 0。
我们也可以直接使用 ls 的 - s 参数查看文件实际占用空间大小:
~$ ls -slh sparse_file 0 -rw-rw-r-- 1 fgp fgp 1.0G May 26 15:47 sparse_file
其中 *** 列为实际占用磁盘空间大小,第 6 列为文件大小(虚拟大小)。
另外使用 truncate 命令可以随意调节文件大小(如果该文件不存在则会自动创建),比如:
~$ 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 文件大小调为 1TB,实际上就是往后面追加空洞(extended part (hole) reads as zero bytes), 因此不会占用实际磁盘空间。当然也可以缩小文件大小,但是如果比文件数据占用空间还小的话,就会截取数据,因此部分数据会丢失。
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 文件进行处理。
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 创建了一个 sparse 文件,然后通过 sed 命令把 Hello 改为 HELLO,我们期望能够保留该文件的 sparse 特性,但实际上我们发现仅仅修改了该文件的一行数据,该文件的空洞被填满,瞬间占用磁盘空间为 1G。一个只有 4K 大小的文件使用 sed 命令后变成了 1G,这让人感到莫名其妙不是吗?
再比如我们我们使用 tar 命令对文件进行归档:
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
以上我们创建了一个 1G 的 sparse 文件,当使用 tar 直接归档时发现该文件变成了非 sparse 文件,占用了 1G 的磁盘空间。而使用 xz 压缩时,虽然解决了存储空间的问题,同时也带来压缩时间开销问题(耗费了 1 分钟的时间进行压缩)。
接下来介绍下熟悉的经典命令 cp,cp 命令可谓无人不知。众所周知,它用于在本地拷贝文件。值得庆幸 (为什么庆幸,因为并不是所有的命令都支持该特性) 的是 cp 命令能够自动探测文件是否 sparse 文件,空洞数据不会拷贝,并且能够保留 sparce 文件副本的稀疏性质:
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 用于远程拷贝文件(远程传输文件):
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
我们发现 scp 不能识别 sparse 文件,传输一个 sparse 文件时会自动填满空洞,发送整个文件内容。
其实 cp 命令有一个针对 sparse 文件拷贝优化的参数 –sparse=WHEN,其中 WHEN 的合法值为 auto、always、never,默认为 auto,能自动识别是否 sparse 文件。如果设置为 never 则会自动填满数据,拷贝整个文件:
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 填满了空洞,相当于把 sparse 文件转化成了非 sparse 文件。
如果指定为 always,则 cp 会尝试把文件转换为 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
由结果发现,我们把非 sparse 文件 sparse_file.copy 转成了 sparse 文件 sparse_file.copy.3。
注:cp 命令黑科技,cp 实现 sparse 文件的相互转换!
其实除了 cp 命令,我们上面的 tar 命令也支持 ndash;sparse 参数:
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
对比前面的结果,我们发现使用 tar 的 -S(ndash;sparse)参数很好的处理 sparse 文件。
另外 cpio 也支持同样的参数,但可惜的是 scp 命令不支持,因此我们使用 scp 远程传输大量的 sparse 文件时效率极低,并且浪费大量网络空间。比如我们经常使用 qemu-img 创建了一个 40GB 的 raw 文件,然后需要拷贝镜像到其他机器上,虽然该文件可能只占了 1GB 左右的磁盘空间,可使用 scp 需要传输 40GB 的空间,并且远程需要预留 40GB 的磁盘空间。那有没有高效传输 sparse 文件的方法呢? 实际上,很可惜,好像并没有,不过有比较好的方法,请看下一节内容。
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
遗憾的是,虽然目标文件保留了其 sparse 特性,节省了目标主机的存储空间,但并没有节省网络传输带宽,依然传输了 2GB 的数据,rsync 不能过滤掉空洞数据的传输。
值得一提的是 rsync 有一个参数 –inplace,这个参数能够探测源文件和目标文件是否修改的块,传输时只传递修改的块,当然 *** 次传输文件时,这个参数并没有什么用。但可惜的是 ndash;sparse 参数和 ndash;inplace 参数不能同时使用。通常做法是 *** 次传输文件时,使用 ndash;sparse 参数,之后如果对文件进行了修改,需要同步远程时,使用 ndash;inplace 参数,它只会在原文件的基础上传输更新的块。(可以先在远程目标机器上先使用 truncate 命令创建一个同名的 sparse 文件,再使用 ndash;inplace 参数传递)。
当然如果我们传输的是镜像文件,可以通过 qemu-img 把 raw 格式在本地转化为 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
转化成 qcow2 格式后,不再是 sparse 文件,因此不会存在以上问题。由以上输出我们发现,该文件只有 196K,因此传输量大幅度减少。
到此,相信大家对“Linux 中 sparse 文件处理与传输的方法是什么”有了更深的了解,不妨来实际操作一番吧!这里是丸趣 TV 网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!