为什么 rsync 不进行增量传输

Wak*_*nka 7 scp rsync

我有大约 77MB 的二进制文件:

nupic@nupic-virtualbox:~/VboxSharedFolder/experiments/sync/exp2$ ls -lah src/
total 77M
drwxrwx--- 1 root vboxsf    0 Jun 21 13:31 .
drwxrwx--- 1 root vboxsf 4.0K Jun 21 16:21 ..
-rwxrwx--- 1 root vboxsf  77M May 27  2014 binary.bin
Run Code Online (Sandbox Code Playgroud)

我一直在玩rsync它的 delta 算法功能,看看它是如何工作的。想法是在二进制文件中进行细微的差异,并查看使用多种方法传输了多少数据。为了这些目的,我制作了非常简单的脚本:

#!/bin/bash
# rsync does not trnansfers delta over local by default
sed 's%\x00\x00\x00\x20\x66\x74\x79\x70\x69\x73\x6f\x6d\x00\x00\x02\x00%\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11%' src/binary.bin > dst/binary.bin
strace -f -e trace=read,write -o rw_rsync_local_default.log rsync -avcz --progress src/ dst/

# rsync -no-W should enables delta tranfer no matter if local or remote
sed 's%\x00\x00\x00\x20\x66\x74\x79\x70\x69\x73\x6f\x6d\x00\x00\x02\x00%\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11%' src/binary.bin > dst/binary.bin
strace -f -e trace=read,write -o rw_rsync_local_delta_enabled.log rsync --no-W -avcz --progress src/ dst/

# rsync trnansfers delta over network by default
sed 's%\x00\x00\x00\x20\x66\x74\x79\x70\x69\x73\x6f\x6d\x00\x00\x02\x00%\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11%' src/binary.bin > dst/binary.bin
strace -f -e trace=read,write -o rw_rsync_remote.log rsync -avcz -e "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" --progress src/ nupic@localhost:/home/nupic/VboxSharedFolder/experiments/sync/exp2/dst/

# scp should transfers whole file not delta
sed 's%\x00\x00\x00\x20\x66\x74\x79\x70\x69\x73\x6f\x6d\x00\x00\x02\x00%\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11%' src/binary.bin > dst/binary.bin
strace -f -e trace=read,write -o rw_scp.log scp src/binary.bin nupic@localhost:/home/nupic/VboxSharedFolder/experiments/sync/exp2/dst/

# cp always transfers whole file not delta
sed 's%\x00\x00\x00\x20\x66\x74\x79\x70\x69\x73\x6f\x6d\x00\x00\x02\x00%\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11%' src/binary.bin > dst/binary.bin
strace -f -e trace=read,write -o rw_cp.log cp src/binary.bin dst/binary.bin
Run Code Online (Sandbox Code Playgroud)

然后我有以下循环来评估结果:

for i in *.log; do
  echo $i; cat $i | grep write | awk 'BEGIN {FS="="}{ sum += $2} END {print sum/1024/1024 "MB"}';
  echo "###########";
done
Run Code Online (Sandbox Code Playgroud)

以下是结果:

rw_cp.log
67.8075MB
###########
rw_rsync_local_default.log
146.697MB
###########
rw_rsync_local_delta_enabled.log
66.8765MB
###########
rw_rsync_remote.log
0.0707941MB
###########
rw_scp.log
136.048MB
###########
Run Code Online (Sandbox Code Playgroud)

从这五个实验中,我只有两个是清楚的:

  1. cp写入的字节数与原始文件 ( rw_cp.log)的大小大致相同。
  2. rsync当目的地是远程(通过网络)时使用增量算法 ( rw_rsync_remote.log)

以下是我不清楚的事情:

  1. 为什么调用rsync上都srcdstlocalhost写约两倍字节的原始文件的大小?( rw_rsync_local_default.log)
  2. 为什么--no-W选项rsync不适用于仅传输三角洲srcdstlocalhost如说在这里,为什么它大约整个文件传输还是?( rw_rsync_local_delta_enabled.log)
  3. 奖励:为什么scp传输大约两倍于原始文件大小的字节?我知道有一些加密,但对我来说两倍似乎很大(rw_scp.log)。

ilk*_*chu 4

简而言之,要回答主要问题,rsync似乎要写入双倍的字节数,因为它会产生两个进程/线程来进行复制,并且进程之间有一个流数据,另一个从接收进程到目标文件。

我们可以通过更详细地查看输出来判断这一点strace,文件开头的进程 ID 以及调用中的文件描述符编号write可用于区分不同的写入“流”。

据推测,这是为了本地传输可以像远程传输一样工作,只是源和目标位于同一系统上。


使用类似的东西strace -e trace=process,socketpair,open,read,write会显示一些线程产生,在它们之间创建套接字对,以及打开输入和输出文件的不同线程。

与您类似的测试运行:

$ rm test2
$ strace -f -e trace=process,socketpair,open,close,dup,dup2,read,write -o rsync.log rsync -avcz --progress test1 test2
$ ls -l test1 test2
-rw-r--r-- 1 itvirta itvirta 81920004 Jun 21 20:20 test1
-rw-r--r-- 1 itvirta itvirta 81920004 Jun 21 20:20 test2
Run Code Online (Sandbox Code Playgroud)

让我们分别计算每个线程写入的字节数:

$ for x in 15007 15008 15009  ; do echo -en "$x: " ; grep -E "$x (<... )?write"  rsync.log | awk 'BEGIN {FS=" = "} {sum += $2} END {print sum}'  ; done 
15007: 81967265
15008: 49
15009: 81920056
Run Code Online (Sandbox Code Playgroud)

这与上面的理论非常吻合。我没有检查第一个线程写入的其他 40kB 是什么,但我假设它会打印进度输出,以及有关同步文件 rsync 的任何元数据都需要传输到另一端。


我没有检查,但我建议即使启用了增量压缩,也许 rsync 的“远程”端仍然会完整写出(大部分)文件,从而导致与 cp 大约相同的写入量。rsync线程之间的传输较小,但最终输出仍然相同。