我有大约 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
我一直在玩rsync
它的增量算法功能,看看它是如何工作的。想法是在二进制文件中做出微小的差异,并查看使用多种方法传输了多少数据。为了这些目的,我制作了非常简单的脚本:
#!/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
然后我有以下循环来评估结果:
for i in *.log; do
echo $i; cat $i | grep write | awk 'BEGIN {FS="="}{ sum += $2} END {print sum/1024/1024 "MB"}';
echo "###########";
done
结果如下:
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
###########
从这五个实验中,我只有两个是清楚的:
cp
写入的字节数与原始文件的大小大致相同 (rw_cp.log
)。rsync
当目的地是远程的(通过网络)时使用增量算法 (rw_rsync_remote.log
)
以下是我不清楚的事情:
- 为什么调用
rsync
on Bothsrc
和dst
onlocalhost
write 大约是原始文件大小的两倍字节? (rw_rsync_local_default.log
) - 为什么
--no-W
选项 forrsync
不按规定仅传输 delta forsrc
和dst
onlocalhost
这里为什么它仍然传输大约整个文件? (rw_rsync_local_delta_enabled.log
) - 额外提示:为什么
scp
传输的字节数大约是原始文件大小的两倍?我知道有一些加密,但两次对我来说似乎很大(rw_scp.log
)。
答案1
简而言之,要回答主要问题,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
让我们分别计算每个线程写入的字节数:
$ 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
这与上面的理论非常吻合。我没有检查第一个线程写入的其他 40kB 是什么,但我假设它打印进度输出,以及有关同步文件 rsync 的任何元数据需要传输到另一端。
我没有检查,但我建议即使启用了增量压缩,也许 rsync 的“远程”端仍然会完整写出(大部分)文件,从而导致与 cp 大约相同的写入量。 rsync线程之间的传输较小,但最终输出仍然相同。
答案2
默认情况下,出于各种安全原因,rsync 首先创建目标文件的新副本,然后替换它。您可以通过指定--inplace
和 来覆盖它--no-whole-file
。这告诉 rsync 对目标文件进行就地编辑,接受手册页中记录的各种风险(对于这种情况通常较小)。