不会溢出到硬件资源的动态流压缩?

不会溢出到硬件资源的动态流压缩?

我有 200 GB 可用磁盘空间、16 GB RAM(其中约 1 GB 被桌面和内核占用)和 6 GB 交换空间。

我有一个 240 GB 外部 SSD,其中 70 GB 已使用,其余部分空闲,我需要将其备份到我的磁盘。

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

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

man pipe:

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

我将 a 想象|成一个真正的管道——一个应用程序将数据推入管道队列,另一个应用程序尽快从管道队列中取出数据。

当左侧的程序写入的数据比管道另一侧处理数据的速度要快时,会发生什么情况?是否会导致内存或交换空间使用量过大,或者内核是否会尝试在磁盘上创建 FIFO,从而填满磁盘?或者SIGPIPE Broken pipe如果缓冲区太大,它会失败吗?

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

  1. 如果将比一次读取的数据更多的数据推入管道,会产生什么影响和结果?
  2. 将数据流压缩到磁盘而不将整个未压缩的数据流放在磁盘上的可靠方法是什么?

注 1:我不能只精确复制前 70 个已使用的 GB 并期望获得一个工作系统或文件系统,因为碎片和其他因素需要完整的内容完好无损。

答案1

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,然后发出 awrite()并在运行时等待一分钟sleep。这就是管道两侧平衡的方式:如果写入过程太快,内核会阻止写入;如果读取过程太快,内核会阻止读取。

答案2

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

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

如果你确实使用dd,你应该总是使用大于默认的块大小dd bs=1M,否则就会遭受系统调用地狱(dd默认的块大小是512字节,因为它的read()s和write()s是4096每个系统调用MiB,开销太大)。

gzip -9使用了更多的CPU,但几乎没有什么可展示的。如果gzip减慢速度,请降低压缩级别,或使用不同的(更快)压缩方法。

如果您正在执行基于文件的备份而不是dd图像,则可能有一些逻辑来决定是否压缩(对于各种文件类型这样做是没有意义的)。dar( taralternative`) 就是一个可以选择这样做的示例。

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

或者,对于某些文件系统,存在只能对已使用区域进行映像的程序。

答案3

除了性能之外,没有任何负面影响:管道有一个缓冲区,通常为 64K,之后,对管道的写入将简单地阻塞,直到gzip读取更多数据。

答案4

也许您只需要文件,然后使用 tar。您可以用零填充不包含您想要的任何内容的块,有人已经问过了。用零清除未使用的空间(ext3、ext4)

然后,pigz通常比gzip.

相关内容