Rsync核心算法
Rsync是unix/linux下同步文件的一个高效算法,它能同步更新两台计算机的文件与目录,并查找文件中的不同块以减少数据传输。Rsync的一个重要特性就是只对变更部分进行传送。rsync可拷贝、显示目录属性以及拷贝文件,并可选择性的压缩以及递归拷贝。Rsync是由Andrew Tridgell发明的。
Rsync要解决差异化同步,前提就必须知道源文件和目标文件之间的差异,特别是当源文件与目标文件分别位于两台计算机上时。
Rsync的算法流程:
1) 分块CheckSum算法:将目标文件按指定块大小平均分成若干块,然后对每块计算两个CheckSum值。涉及的两个算法如下:
a) Rolling CheckSum,32位,采用Adler-32算法;比较弱,碰撞几率高;
b) MD5 HASH,128位,强CheckSum,碰撞几率低;
显然,如果Rolling CheckSum 值不同,那么两个文件块肯定不同;但是,如果Rolling CheckSum 值相同,但因其高碰撞率我们无法确定两个文件块就是相同的,这时就需要进一步比较MD5的值了,毕竟MD5的碰撞几率达到2* 因此,可以说:Adler-32用来区别不同,而MD5用来进一步确认相同。
2) 目标文件的CheckSum计算完成后,接下来同步目标端就需要将这个CheckSum列表告诉给源文件端,给其提供一个差异检查的参照物。这个列表的每一项都包含以下三个信息:Rolling CheckSum、MD5、文件块号。同步源端拿到这个列表后,对源文件进行同样的CheckSum,然后对比,就可以知道哪些文件块发生了变化。仅仅如此简单吗?我们接着看下面这两个问题:
a) 如果在源文件中间插入了一个字符,其后的文件块都将偏移一个字符,显然和目标文件已经不同了,CheckSum信息也发生了改变。但从理论上将,我们应该只传输一个字符到目标端。怎么解决呢?
b) 如果目标文件很大,对应的CheckSum列表也将很长,在对源文件进行CheckSum比较时采用线性查找,显然比较慢。又该怎么办?
3) 查找算法。同步源端拿到目标文件的CheckSum列表后,将之存到一个Hash Table中,用Rolling Checksum做Hash-Key,以便获得O(1)时间复杂度的查找性能。这个Hash Table是16bits的,所以,Hash Table的大小是2^16,对Rolling Checksum的Hash会被散列到0 到 2^16 – 1中的某个整数值。显然,Hash表中的KEY会发生碰撞,我们只需要将碰撞的Checksum做成一个链表就可以了。
4) 比对算法。这是最关键的算法,细节如下:
a) 取源文件的第一个文件块(长度设为N),即从源文件的第1个字节到第N个字节计算Rolling CheckSum,然后到HASH表中查找;
b) 如果查到了,表明源文件与目标文件中有潜在相同的文件块;继续计算MD5并比较。如果Rolling checksum和MD5都相同,可确定相同文件块存在,