rsync要解决什么?
比较两台不同机器上的两个文件。如果是同一台机器上的文件,可以直接用diff命令
如何解决?
1
最笨的办法是把两个文件放到同一台机器上,这样就可以直接用diff比较了
但是这需要把一个文件完整地传输到另一台机器上,显然是比较费时间的
我们改进一下
2
用文件校验和代替文件。传输的不再是文件本身,而是对文件做校验和后得到的哈希值,这样只需要传一个字符串就行了
这个方法只能区分文件是否一样,至于是哪部分不同是不清楚的
我们再改进一下
3
把文件切块,分别比对每块的校验和,这样就能用较小代价找到差异部分了
但实际上这个思路是行不通的
假设两个文件现在是相同的,大小为1G,我们按每块1M大小进行分割,得到的是1024组1M的数据块。这1024组数据块两两都是相同的
此时我在A文件头部加1K的内容、B文件不动,我希望得到的结果是新增的1K所在的块被标识出来,其他的块还是两两相同的。
但是分块的时候程序并不知道这1K在哪,所以只能按默认的顺序分块,最终结果就是1025组数据块都是不相同的。
问题出在哪里?
对文件的分块形式规定的太死板了
而对文件的修改是很自由的,文件的每个位置都可以被修改
所以我们希望对文件的分块同样可以自由一些
4
rsync是这么做的
对于A文件依然是正常分块,而在计算B文件时改成了一个滑动窗口。
滑动窗口的逻辑很简单,假设窗口长度设置为n,那么第一次窗口里的块就是(1,n)。如果当前窗口里的块的校验和能和A文件中的某个校验和对应,那就认为这组块是相同的,窗口跳到下一个块(n+1,2n)继续校验;如果找不到对应的校验和,就向后滑动一个单位到(2,n+1)继续校验。
此外rsync为了提高速度,做了很多优化:
- 校验和用了两个,32位的弱校验和和128位的强校验和。
在校验时先检查弱校验和再检查强校验和。
其中弱校验和是用于验证两个块是否不同,如果相同,32位不足以保证数据块是一致的,继续计算强校验和
强校验和是用于验证两个块是否相同,128位足够保证数据的一致性 - 优化了弱校验和的算法
基于Mark Adler的adler-32 checksum算法设计出的rolling checksum算法。rolling checksum算法的优势是在已知(1,n)块的校验和时可以快速计算(2,n+1)的校验和而不是全部重新计算 - 使用哈希表存放A文件所有的校验和,便于B文件快速查找
官方文档:The rsync algorithm (samba.org)
命令行使用介绍:第2章 rsync(一):基本命令和用法 - 骏马金龙 - 博客园 (cnblogs.com)、man rsync翻译(rsync命令中文手册) - 骏马金龙 - 博客园 (cnblogs.com)