当前位置: 首页 > 科技观察

Linux文件系统中稀疏文件的处理与传输

时间:2023-03-20 00:56:10 科技观察

0.什么是稀疏文件?资源,为了提高资源利用率,不会分配实际的存储空间,只有在真正写入数据的时候,操作系统才会真正一点一点地分配空间,比如一次分配64KB。所以这个文件看起来很大,但是占用的空间很小,实际占用的空间只和用户填写的数据量有关。文件看起来像一个大盒子,但里面可能装的东西不多,而且有一个大洞,所以称为稀疏文件(Sparsefile)。稀疏文件是Linux文件系统的一项高级功能,可以使磁盘过载。它最经典的应用是为虚拟机创建虚拟硬盘和数据库快照。比如我们使用qemu-img创建一个大小为20GB的raw文件(注意qcow2格式不是稀疏文件):fgp@node1:~$qemu-imgcreate-frawtest.raw20GFormatting'test.raw',fmt=rawsize=21474836480fgp@node1:~$qemu-imginfotest.rawimage:test.rawfileformat:rawvirtualsize:20G(21474836480bytes)disksize:0ormore我们使用qemu-img创建一个20G的镜像文件,如图qemu-imginfo,virtualsize就是我们分配的空间大小,disksize就是实际占用的空间,一开始不占用任何磁盘空间。注意:qemu-imgcreate-fraw等同于`truncate-s20Gtest.raw'。当然,也会有问题。例如,系统生成了一堆稀疏文件。如果文件系统已满,这些文件将无法写入。为了避免这种情况,需要控制稀疏文件的数量。1、如何判断一个稀疏文件是否为稀疏文件?除了上述图像文件外,其他文件类型也可能是稀疏文件。如何判断一个稀疏文件是否为稀疏文件?最简单的方法是分别使用ls命令和du命令查看大小。如果两者大小不一致,说明是稀疏文件。我们可以使用dd命令快速生成一个稀疏文件:ddif=/dev/zeroof=sparse_filebs=1Mseek=1024count=0上面的命令从第1024*1M(相当于中间1GB空间)开始写入文件,并且写入/dev/zero,实际上写入了0个块(count=0),因此实际上没有写入任何数据。我们使用ls-lh查看其大小:~$ls-lhsparse_file-rw-rw-r--1fgpfgp1.0GMay2615:47sparse_file可以看出文件显示为1G。我们再使用du-h命令查看其占用的磁盘空间:~$du-hsparse_file0sparse_file发现实际占用的磁盘空间为0,也可以直接使用ls的-s参数查看实际占用的空间文件:~$ls-slhsparse_file0-rw-rw-r--1fgpfgp1.0GMay2615:47sparse_file其中***是实际占用的磁盘空间,第6列是文件大小(虚拟大小)。另外,使用truncate命令随意调整文件大小(如果文件不存在,会自动创建),例如:~$truncate--size1Tsparse_file~$du-hsparse_file0sparse_file~$ls-lhsparse_file-rw-rw-r--1fgpfgp1.0TMay2616:09sparse_file上面我们将sparse_file文件的大小调整为1TB,其实就是在后面加上空洞(扩展部分(空洞)读作零字节),所以不会占用实际磁盘空间。当然也可以减小文件大小,但是如果小于文件数据占用的空间,数据就会被截取,所以会丢失一些数据。truncate-s500Msparse_file~$ls-lhsparse_file-rw-rw-r--1fgpfgp500MMay2616:12sparse_file上面我们将文件减少到500MB。2、稀疏文件处理稀疏文件的处理也存在一些问题。例如,我们使用sed来处理一个稀疏文件。fgp@node1:~/tmp$echo"HelloWorld">test.rawfgp@node1:~/tmp$truncate-s1Gtest.rawfgp@node1:~/tmp$ls-slhtotal68K4.0K-rw-rw-r--1fgpfgp1。0GMay2814:52test.rawfgp@node1:~/tmp$sed-i's/Hello/HELLO/g'test.rawfgp@node1:~/tmp$ls-slhtotal1.1G1.1G-rw-rw-r--1fgpfgp1.0GMay2814:53test.raw上面我们使用truncate创建了一个稀疏文件,然后通过sed命令将Hello改为HELLO。我们期望保留文件的稀疏特征,但实际上我们发现文件中只有一行数据被修改了。坑填了,瞬间占用磁盘空间1G。一个只有4K大小的文件,使用sed命令后变成了1G。是不是莫名其妙?再比如我们使用tar命令来归档文件:fgp@node1:~/tmp$qemu-imgcreate-frawtest.raw1GFormatting'test.raw',fmt=rawsize=1073741824fgp@node1:~/tmp$timetar-cftest.tartest.rawreal0m2.145suser0m0.012ssys0m1.640sfgp@node1:~/tmp$timetar-cJftest.tar.xztest.rawreal1m0.692suser0m59。060ssys0m1.048sfgp@node1:~/tmp$ls-lshtotal1.1G0-rw-r--r--1fgpfgp1.0GMay2815:37test.raw1.1G-rw-rw-r--1fgpfgp1.1GMay2815:37test.tar156K-rw-rw-r--1fgpfgp153KMay2815:39test.tar.xz上面我们创建了一个1G的稀疏文件,直接用tar压缩的时候,发现文件变成了非稀疏文件,占用了1G的磁盘空间。使用xz压缩时,虽然解决了存储空间的问题,但是也带来了压缩时间开销的问题(压缩需要1分钟)。接下来介绍大家耳熟能详的经典命令cp,cp命令大家都耳熟能详了。众所周知,它是用来在本地复制文件的。还好(为什么,因为不是所有的命令都支持这个特性)cp命令可以自动检测一个文件是否是稀疏文件,空的数据不会被复制,可以保留稀疏文件副本的稀疏性:fgp@node1:~$cpsparse_filesparse_file.copyfgp@node1:~$ls-slhsparse_file*0-rw-rw-r--1fgpfgp2.0GMay2616:39sparse_file0-rw-rw-r--1fgpfgp2.0GMay2616:39sparse_file.copy让我们来看看类似于cp命令命令scp,scp用于远程复制文件(远程传输文件):fgp@node1:~$scpsparse_filelocalhost:~/sparse_file.copysparse_file100%2048MB97.5MB/s00:21fgp@node1:~$ls-slhsparse_file*0-rw-rw-r--1fgpfgp2.0GMay2616:39sparse_file2.1G-rw-rw-r--1fgpfgp2.0GMay2616:42sparse_file.copy我们发现scp无法识别稀疏文件,在传输稀疏文件时,会自动填补漏洞并发送整个文件内容。其实cp命令有一个参数--sparse=WHEN针对复制稀疏文件进行了优化,其中WHEN的合法值为auto、always、never,默认为auto,可以自动识别稀疏文件或者不是。如果设置为never,会自动补全数据,复制整个文件:fgp@node1:~$cp--sparse=neversparse_filesparse_file.copy.2fgp@node1:~$ls-lhssparse_file*0-rw-rw-r--1fgpfgp2.0GMay2616:39sparse_file2.1G-rw-rw-r--1fgpfgp2.0GMay2616:42sparse_file.copy2.1G-rw-rw-r--1fgpfgp2.0GMay2616:50sparse_file.copy.2可见sparse_file.copy。2补洞,相当于将稀疏文件转为非稀疏文件。如果指定为always,cp将尝试将文件转换为稀疏文件以减少磁盘空间:fgp@node1:~$cp--sparse=alwayssparse_file.copysparse_file.copy.3fgp@node1:~$ls-lshsparse_file*0-rw-rw-r--1fgpfgp2.0GMay2616:39sparse_file2.1G-rw-rw-r--1fgpfgp2.0GMay2616:42sparse_file.copy2.1G-rw-rw-r--1fgpfgp2.0GMay2616:50sparse_file.copy.20-rw-rw-r--1fgpfgp2.0GMay2616:52sparse_file.copy.3结果发现我们将非稀疏文件sparse_file.copy转换成了稀疏文件sparse_file.copy.3。注意:cp命令是黑科技,cp实现稀疏文件相互转换!其实我们上面的tar命令除了cp命令外,还支持-sparse参数:-cSJftest.tar.xztest.rawreal0m0.011suser0m0.000ssys0m0.008sfgp@node1:~/tmp$ls-slhtotal16K0-rw-r--r--1fgpfgp1.0GMay2815:37test.raw12K-rw-rw-r--1fgpfgp815:May2K42test.tar4.0K-rw-rw-r--1fgpfgp184May2815:43test.tar.xz对比前面的结果,我们发现使用tar的-S(--sparse)参数可以很好的处理稀疏文件。另外cpio也支持同样的参数,可惜scp命令不支持,所以当我们使用scp远程传输大量稀疏文件时,效率极低,浪费了大量的网络空间。比如我们经常使用qemu-img创建一个40GB的raw文件,然后需要将镜像复制到其他机器上。虽然文件可能只占用1GB左右的磁盘空间,但是scp需要传输40GB的空间,而remote需要预安装留下40GB的磁盘空间。有没有办法有效地传输稀疏文件?其实很遗憾,好像没有办法,但是有更好的办法,请看下一节。3、比较高效的稀疏文件传输方式前面我们说过scp不支持稀疏文件的处理。好在rsync命令支持稀疏文件处理:fgp@node1:~$rsync-av--sparse--progresssparse_filelocalhost:~/sparse_file。copyfgp@localhost'spassword:sendingincrementalfilelistsparse_file2,147,483,648100%74.67MB/s0:00:27(xfr#1,to-chk=0/1)sent2,148,008,037bytesreceived35bytes66,092,556.06bytes/sectotalsizegis2,164.8:speed13pnodef13,148,008,037bytesreceived~$ls-lhssparse_file*0-rw-rw-r--1fgpfgp2.0GMay2616:39sparse_file0-rw-rw-r--1fgpfgp2.0GMay2616:39sparse_file.copy不幸的是,目标文件虽然保留了它的稀疏特征,节省了存储空间目标主机不节省网络传输带宽,依然传输2GB的数据,rsync无法过滤掉空数据的传输。值得一提的是rsync有一个参数--inplace,这个参数可以检测源文件和目标文件是否是修改过的块,传输时只传输修改过的块。当然这个参数在第一次传输文件的时候是没有用的。不幸的是,--sparse参数和--inplace参数不能同时使用。通常的做法是在第一次传输文件时使用--sparse参数。如果后面修改了文件,需要远程同步,使用--inplace参数,只会在原文件的基础上传输更新的块。(可以先用truncate命令在远程目标机器上创建一个同名的稀疏文件,然后用--inplace参数传递)。当然,如果我们是传输图片文件,我们可以使用qemu-img在本地将raw格式转换成qcow2格式再传输:fgp@node1:~/tmp$ls-lshtotal00-rw-rw-r--1fgpfgp10GMay2815:00测试。rawfgp@node1:~/tmp$qemu-imgconvert-fraw-Oqcow2test.rawtest.qcow2fgp@node1:~/tmp$ls-lshtotal196K196K-rw-r--r--1fgpfgp193KMay2815:12test.qcow20-rw-rw-r--1fgpfgp10GMay2815:00test.raw转换为qcow2格式后,不再是稀疏文件,所以不会存在上述问题。从上面的输出我们发现文件只有196K,所以传输量大大减少了。【本文为专栏作家“傅光平”原创文章,如需转载请get联系】点击查看更多该作者好文