ddrescue,“磁盘大小”小于总大小,写入 NTFS 时可能会影响性能

ddrescue,“磁盘大小”小于总大小,写入 NTFS 时可能会影响性能

背景故事在我之前的问题中我自己的答案

有一次我创建了两个部分图像ddrescue:一个文件在 NTFS 文件系统上,另一个在 ext4 上。

我很早就注意到,两个映像的“磁盘大小”远低于总大小,这表明(如果我没记错的话)这些文件已被写入“稀疏”,即空数据实际上并未分配到相应的卷上,只有已恢复的数据才被考虑在内。但我从未-Sddrescue命令中使用过开关,该开关指定输出文件应写入“稀疏”。

旁注:我所做的是-R在开始时使用开关(“反向”),认为它会立即分配输入硬盘的整个大小(想法是它将产生一个“更干净”的输出,将所有数据按顺序写入接收分区,以便即使文件系统出现问题并且我必须恢复恢复,也能保持映像文件的完整性……);它确实将文件的显示大小增加到 931.5GB,但实际上“磁盘上的大小”仅增加了在此步骤中复制的少量数据。

因此主要问题是:如何解释这种稀疏性?为什么ddrescue默认情况下复制不是连续的?

然后,由于我有两张部分图像,每张都包含另一张所缺少的一些有效数据,因此我执行以下操作:

  • 我尝试将 ext4 分区上第二个映像中缺失的挽救区域复制到 NTFS 分区上的第一个映像中,这两个映像位于同一个健康的 2TB 硬盘上(Seagate ST2000DX001,最大写入速度接近 200MB/s),速度应该非常快。但结果发现速度非常慢:只有 660KB/s。
  • 于是我停下来,做了相反的事情:我将ddrescue第一个映像(在 NTFS 上)中挽救的区域(第二个映像中缺失的区域)复制到第二个映像(在 ext4 上)。现​​在我得到的复制速率为 43000KB/s 或 43MB/s,这要高得多,更接近该级别和容量的同一硬盘内的正常复制速率。

第二个问题:这种奇怪的行为是否与我在写入 NTFS 时遇到的性能问题有关?Linux NTFS 驱动程序是否已知在处理大型“稀疏”文件时会遇到麻烦?

答案1

这个答案调查了行为ddrescue以解决主要问题。如果你对测试过程不感兴趣,那么你可以直接跳到结尾处的我的结论和解释。

测试平台

$ uname -a
Linux foo 4.2.0-27-generic #32~14.04.1-Ubuntu SMP Fri Jan 22 15:32:26 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

$ cat /etc/issue
Ubuntu 14.04.5 LTS \n \l

$ ddrescue -V
GNU ddrescue 1.17

文件系统是 btrfs;只要它支持稀疏文件,那就没关系。

测试

首先我得到了8MiB的随机数据:

dd if=/dev/urandom of=random.chunk bs=1M count=8

然后我把它做成一个环回设备并记住了它的名字:

loopdev=`sudo losetup -f --show random.chunk`

接下来我又制作了另一个装置,它由

  • 块 0:不可读,1 MiB
  • 块 1:零,2 MiB
  • 块 2:不可读,4 MiB
  • 块 3:来自的数据random.chunk,8 MiB
  • 块 4:不可读,16 MiB

代码(它使用这里的文件句法):

sudo dmsetup create mydevice << EOF
    0  2048 error
 2048  4096 zero
 6144  8192 error
14336 16384 linear $loopdev 0
30720 32768 error
EOF

我确认gdisk -l /dev/mapper/mydevice总大小应该是 31 MiB。

实际读取是通过以下方式完成的:

ddrescue     /dev/mapper/mydevice  normal.raw  normal.log
ddrescue -R  /dev/mapper/mydevice normalR.raw normalR.log
ddrescue -S  /dev/mapper/mydevice  sparse.raw  sparse.log
ddrescue -RS /dev/mapper/mydevice sparseR.raw sparseR.log

结果ls -hls *.raw

 10M -rw-rw-r-- 1 kamil kamil 15M Sep 10 00:37 normal.raw
 10M -rw-rw-r-- 1 kamil kamil 15M Sep 10 00:37 normalR.raw
8.0M -rw-rw-r-- 1 kamil kamil 15M Sep 10 00:37 sparse.raw
8.0M -rw-rw-r-- 1 kamil kamil 15M Sep 10 00:37 sparseR.raw

为确保万无一失,我确认了cmp这四个文件在读取时是完全相同的。四个日志文件包含相同的错误扇区和健康扇区图。

请注意

  • 15 MiB 表示最后一个块丢失;
  • 10MiB表示块1和块3;
  • 8MiB仅表示块3。

打扫

sudo dmsetup remove mydevice
sudo losetup -d $loopdev
unset loopdev
rm random.chunk normal.raw normal.log normalR.raw normalR.log sparse.raw sparse.log sparseR.raw sparseR.log

结论

  • 当谈到文件大小时,是否反向读取(-R)并不重要。
  • 输入文件最末端的不可读块不会影响输出文件的整体大小。
  • 不可读的块确实会影响整个文件的大小,但它们总是很稀疏(当然,如果目标文件系统支持这一点)。
  • -S选项仅影响从输入文件中实际读取的零块。

解释

以上是事实。这部分更像是我的观点。

ddrescue只要无需额外工作,它似乎就会尽力为您节省磁盘空间。当您使用-S该工具时,必须进行一些计算来检查给定的数据块是否全为零。如果出现读取错误,它不需要计算任何内容,它可以使输出文件中的片段稀疏,而无需任何成本。

解决方案

你写了:

在开始时使用-R开关(“反向”),认为它会立即分配输入硬盘的整个大小

我们刚刚看到这是一个错误的假设。事实上,你描述了什么-p是错误的。ddrescue -p将为输出文件预先分配磁盘空间。当我在测试期间执行此操作时,输出文件有 31 MiB 并且并不稀疏(即使有-S)。

答案2

我自己做了一个不同的测试。

– 我创建了一个简单的模板 ddrescue 日志/映射文件,其中包含以下内容:

0x00000000  0x100000  ?
0x100000  0x3FE00000  +
0x3FF00000  0x100000  ?

(这意味着:在总共 1GB 的数据中,第一个和最后一个 MB 还没有被尝试,其余的被视为“已拯救”。)

– 我使用该日志/映射文件运行了 ddrescue,使用以下命令(以从该 1TB HDD 的恢复中拯救出来的图像作为输入,将输出切割为 1GB):

ddrescue -s 1073741824 [rescued_image_file] [test1GB] [test1GB.log]

生成的 [test1GB] 文件的总大小正如预期的那样为 1GB,但“磁盘大小”为 2MB,这意味着只分配了实际复制的数据(第一个和最后一个 MB)。

– 然后我以该 1GB 文件作为输入运行 ddrescue,这次没有使用模板,先不使用模板,然后使用 -S 开关(“稀疏写入”)。

ddrescue [test1GB] [test1GB-NS] [test1GB-NS.log]
ddrescue -S [test1GB] [test1GB-S] [test1GB-S.log]

看起来:

  • [test1GB-NS](非稀疏)的“磁盘大小”为 1GB - 因此整个文件都已被分配和复制,甚至空扇区也是如此;然而...
  • [test1GB-S](稀疏)的“磁盘大小”仅为 1.2MB 或 1114112 字节 - 这意味着尚未分配空扇区,即使是包含在第一个和最后一个 MB 中的扇区也是如此。

我认为“稀疏性”是一个全有或全无的概念,就像文件压缩一样,但显然存在“部分稀疏”文件这样的东西,而且 ddrescue 确实似乎通过这种方式节省了空间 - 这不一定是一个优势(并且可能确实会对性能产生影响);应该有一个开关让它动态分配输出文件的全部大小(而不是预先分配,如果输入很大,这可能会很长),就像它(显然)直接写入设备或分区时一样。

相关内容