强制rsync逐字节比较本地文件而不是校验和

Force rsync to compare local files byte by byte instead of checksum

我写了一个Bash脚本来备份一个文件夹。脚本的核心是一条rsync指令

rsync -abh --checksum /path/to/source /path/to/target

我使用--checksum是因为我不想依赖文件大小和修改时间来确定源路径中的文件是否需要备份。然而,大多数——如果不是全部的话——我在本地 运行 这个脚本,即连接了一个包含备份目标文件夹的外部 USB 驱动器;没有网络备份。因此,不需要增量传输,因为两个文件将完全由同一台机器读取和处理。在这种情况下,计算校验和甚至会降低速度。如果 rsyncdiff 文件都存储在本地会更好。

阅读联机帮助页后,我偶然发现了 --whole-file 选项,它似乎避免了代价高昂的校验和计算。联机帮助页还指出,如果源和目标是本地路径,这是默认设置。

所以我正在考虑将我的 rsync 声明更改为

rsync -abh /path/to/source /path/to/target

现在 rsync 会逐字节检查本地源文件和目标文件,还是会使用修改时间 and/or 大小来确定是否需要备份源文件?我绝对不想依靠文件大小或修改时间来决定是否应该进行备份。

更新

注意rsync指令中的-b选项。这意味着目标文件将在被替换之前进行备份。因此, 盲目地 rsync'ing 源文件夹中的所有文件,例如,按照评论中的建议提供 --ignore-times,不是一种选择。它会创建太多重复文件并浪费存储空间 space。另请记住,我正在尝试减少本地计算机上的备份时间和工作量。仅备份所有内容会破坏该目的。

所以我的问题可以改写为,rsync 是否能够逐字节进行文件比较?

无法像您期望的那样逐字节比较文件而不是校验和。

rsync 的工作方式是创建两个进程,即发送方和接收方,这两个进程创建文件列表及其元数据以相互决定哪些文件需要更新。即使在本地文件的情况下也是如此,但在这种情况下,进程可以通过管道而不是网络套接字进行通信。更改文件列表确定后,更改将作为增量文件或整个文件发送。

理论上,一个人可以将文件列表中的整个文件发送给另一个人以进行比较,但在实践中,这在许多情况下效率很低。接收器需要将这些文件保存在内存中,以防它检测到需要更新文件,否则需要重新发送文件中的更改。这里的任何可能的解决方案听起来都不是很有效。

关于 rsync 的(理论)力学有一个很好的概述:https://rsync.samba.org/how-rsync-works.html

Question: is rsync capable of doing a file comparison on a byte by byte basis?

严格来说,是的:

  • 这是一个逐块比较,但您可以更改块大小。
  • 你可以使用 --block-size=1,(但它 不合理 低效且不适合基本上每个人)

基于块的滚动校验和是网络上的默认行为。

使用 --no-whole-file 选项在本地强制执行此行为。 (见下文)

Statement 1. Calculating the checksums even introduces a speed down in this case.

这就是本地传输默认关闭的原因。

使用 --checksum 选项强制读取整个文件,而不是默认的逐块增量传输校验和检查

Statement 2. Will rsync now check local source and target files byte by byte or
       will it use modification time and/or size to determine if the source file        needs to be backed up?

默认情况下它将使用大小和修改时间。

您可以组合使用 --size-only--(no-)ignore-times--ignore-existing
--checksum 修改此行为。

Statement 3. I definitely do not want to rely on file size or modification times to decide if a        backup should take place.

那么你需要使用--ignore-times and/or --checksum

Statement 4. supplying --ignore-times as suggested in the comments, is not an option

也许使用 --no-whole-file --ignore-times 是你想要的吗?这强制使用增量传输算法,但对于 每个 文件,无论时间戳或大小如何。

你(在我看来)只有在避免无意义的写入至关重要的情况下才会使用这种选项组合(尽管重要的是特别是无意义的写入你'重新尝试避免,不是系统的效率,因为对本地文件进行增量传输实际上不会更有效), 有理由相信具有相同修改标记和字节大小的文件确实可能不同。

我看不出以字节为单位的修改戳记和大小只是识别已更改文件的合乎逻辑的第一步。

如果您比较了以下两个文件:

  • 文件1(本地) : File.bin - 79776451 bytes 并在15 May 07:51
    [=162=上修改]
  • 文件 2(远程):File.bin - 79776451 bytes 并在 15 May 07:51
  • 上修改

默认行为是跳过这些文件。如果您对跳过这些文件不满意,并希望比较它们,您可以强制 使用 --no-whole-file --ignore-times

对这些文件进行逐块比较和差异更新

所以关于这一点的总结是:

  1. 使用默认方法进行最有效的备份和存档
  2. 使用--ignore-times--no-whole-file强制增量更改(逐块校验和,仅传输差异数据)如果出于某种原因这是必要的
  3. --checksum--ignore-times完全是偏执和浪费

Statement 5. Notice the -b option in the rsync instruction. It means that destination files will be backed up before they are replaced

是的,但这可以随心所欲地工作,它并不 一定意味着每次一个文件时完全备份已更新,当然并不意味着完全传输将发生。

您可以将 rsync 配置为:

  • 保留文件的 1 个或多个版本
  • --backup-dir配置它是一个完整的增量备份系统。

这样做不会浪费 space 除了保留差异数据所需的资源。我可以在实践中验证这一点,因为我的备份驱动器上的 space 不足以让我以前的所有版本成为完整副本。


一些补充信息


为什么增量传输比在本地复制整个文件更有效?

因为您没有跟踪每个文件的更改。如果您确实有一个增量文件,您可以合并只是改变的字节,但是你需要知道什么那些改变的字节是第一个。 了解这一点的唯一方法是阅读整个文件

例如:

  • 我修改了一个 10MB 文件的第一个字节。
  • 我使用 rsync 和增量传输来同步这个文件
  • rsync 立即发现第一个字节(或第一个块中的字节)已更改,并继续(默认 --inplace)仅更改该块
  • 然而rsync不知道它只是第一个字节被改变了。它会一直校验和直到整个文件被读取

出于所有意图和目的:

  • 考虑 rsync 一种工具,该工具 有条件地 根据文件时间戳或大小是否已更改来执行 --checksum。将其覆盖为 --checksum 本质上等同于 --no-whole-file--ignore-times,因为两者都将:
    • 每个文件进行操作,而不考虑时间和大小
    • 读取文件的每个块以确定要同步的块。

那有什么好处呢?

整个事情是传输带宽速度/开销之间的权衡。

  • --checksum 是一种只通过网络发送差异的好方法
  • --checksum 忽略具有相同时间戳和大小的文件是一种很好的方式,既可以通过网络发送差异,又可以最大限度地提高整个备份操作的速度

有趣的是,使用 --checksum 作为一揽子选项可能比 force 更有效 每个文件.

的增量传输