即时流压缩不会溢出到硬件资源中吗?


23

我有200 GB的可用磁盘空间,16 GB的RAM(其中约1 GB被台式机和内核占用)和6 GB的交换空间。

我有一个240 GB的外部SSD,其中70 GB已使用1,其余的则免费,我需要备份到磁盘上。

通常,我会dd if=/dev/sdb of=Desktop/disk.img先将磁盘压缩,然后再压缩它,但首先制作映像不是一个选择,因为这样做会比我需要更多的磁盘空间,即使压缩步骤会导致压缩可用空间,因此最终存档可以轻松放入我的磁盘中。

dd默认情况下会写入STDOUT,并且gzip可以从STDIN读取,因此从理论上讲,我可以进行写入dd if=/dev/sdb | gzip -9 -,但是gzip读取字节所需的时间比dd产生字节的时间长得多。

来自man pipe

写入管道写入端的数据由内核缓冲,直到从管道读取端读取数据为止。

我将一个|虚拟的管道想象成一个真实的管道-一个应用程序将数据放入管道,另一个应用程序将数据尽快从管道队列中取出。

当左侧的程序比管道的另一端希望更快地写入更多数据时,怎么办?它会导致过多的内存使用或交换使用,还是内核会尝试在磁盘上创建FIFO,从而填满磁盘?还是SIGPIPE Broken pipe如果缓冲区太大会失败?

基本上,这可以归结为两个问题:

  1. 将更多数据放入管道中比一次读取更多的含义和结果是什么?
  2. 将数据流压缩到磁盘而不将整个未压缩的数据流放在磁盘上的可靠方法是什么?

注意1:由于碎片等原因,我不能完全复制前70个已使用的GB并期望得到一个工作系统或文件系统,这需要完整的内容。


为什么要备份整个文件系统,而不是仅备份用户目录,还可能备份已安装的非标准软件列表?
jamesqf

5
@jamesqf例如 因为它更容易还原...
deviantfan '17

4
@jamesqf因为这之后我还获得了引导扇区和交换分区,因此我可以完全重新创建磁盘,而不必创建十亿个烦人的文件。

3
随机提示:查看lzop而不是gzip; 它的压缩速度要快得多,压缩率却低得多。我发现它非常适合压缩速度可能成为瓶颈的磁盘映像。
marcelm

1
“当左侧程序比管道另一端希望处理更快的速度写入更多数据时,该怎么办?” 内核将导致写入过程进入睡眠状态,直到管道中有更多空间为止。
塔维安·巴恩斯

Answers:


16

从技术上讲,您甚至不需要dd

gzip < /dev/drive > drive.img.gz

如果使用dd,则应始终使用大于默认块大小的类,dd bs=1M否则将遭受syscall hell(dd默认块大小为512字节,因为它read()write()s分别是4096syscalls的MiB开销,太多了)。

gzip -9使用更多的CPU,却很少显示。如果gzip速度变慢,请降低压缩级别,或使用其他(更快)压缩方法。

如果您要执行基于文件的备份而不是dd映像,则可以使用一些逻辑来决定是否完全压缩(对于各种文件类型,这样做毫无意义)。dartar替代`)是一个可以选择这样做的示例。

如果您的可用空间为零(因为它是在TRIM之后可靠地返回零的SSD,并且您运行fstrim和删除了缓存),则还可以ddconv=sparse标志一起使用以创建未压缩的,可循环装入的稀疏映像,该映像将零磁盘空间用于零区域。要求映像文件由支持稀疏文件的文件系统支持。

可选地,对于某些文件系统,存在能够仅对使用的区域进行成像的程序。


1
“如果你使用的DD,你应该总是比喜欢默认的块大小大走dd bs=1M -你可以,但不要抱太大的期望。在我的PC上,dd以512字节块的速度大约可达到2GB / s。那不是瓶颈。gzip将会。
marcelm

@marcelm我们永远不知道人们在使用哪种机器。如果您dd要以2GB / s的速度使用512字节的块,那么在此过程中如果没有100%占用一个CPU核心,我会感到惊讶。现在,如果您的设备是四核,无论如何它仍然处于闲置状态,那么您可能不会注意到差异。但是,其他所有人仍然这样做。
弗罗斯特斯

9
叹。每当dd提到区块大小时,人们都会挑剔。gzipCPU密集度也是我回答的一部分,好吗?抱歉,我不同意“微不足道”。每次演出可能只会增加1-2s gzip -9(但是在处理数百场演出时仍相当于数分钟),但您的建议lzop -1是每演出1s而不是每演出4s。在土豆(单核虚拟服务器)上进行了测试。添加理智的blocksize不会dd花费任何成本,而且缺点也为零。别挑剔。去做就对了。ymmv
frostschutz

19

dd一次只能读取和写入一个数据块,并且只有一个未完成的数据块。所以

valgrind dd if=/dev/zero status=progress of=/dev/null bs=1M

显示dd使用了大约1MB的内存。您可以valgrind尝试使用块大小,然后拖放,以查看对dd速度的影响。

当您插入时gzipdd只需放慢速度以匹配gzip的速度。它的内存使用量不会增加,也不会导致内核将缓冲区存储在磁盘上(内核不知道如何执行操作,除非通过交换)。仅当管道的一端死亡时,管道才发生破裂。请参阅signal(7)write(2)了解详细信息。

从而

dd if=... iconv=fullblock bs=1M | gzip -9 > ...

是您追求的安全方式。

在进行管道传输时,如果读取过程无法跟上,则写入过程最终会被内核阻止。您可以通过运行查看

strace dd if=/dev/zero bs=1M | (sleep 60; cat > /dev/null)

您会看到dd读取为1MB,然后write()sleep运行时发出一分钟的等待时间。这就是管道双方平衡的方式:如果写入过程太快,内核将阻止写入;如果读取过程太快,则内核将阻止读取。


1
太酷了。哪种机制dd知道减慢匹配gzip速度?它是自动的,就像内核一样,还是从有关其输出文件描述符的元数据中计算出来的?

9
@cat是自动的;dd调用write()以将数据放入管道。write()实际上将控制权转移到内核,以便它可以操纵管道内存。如果内核看到管道已满,它将等待(“阻塞”)直到管道有足够的空间。只有这样,write()调用才能完成,并将控制权转回dd,然后它将再次将数据写入管道。
marcelm


8

回答有关其工作原理的实际问题:“如果左侧的程序比管道的另一端更快地写入更多数据,该如何处理呢?”

这不会发生。管道中有一个很小的有限大小的缓冲区。请参阅管道缓冲区有多大?

一旦管道缓冲区已满,发送程序就会阻塞。进行写调用时,内核将不会将控制权返回给程序,直到将数据写入缓冲区为止。这为读取程序CPU提供了清空缓冲区的时间。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.