"文件系统迁移方法研究--rsync"

  "rsync工作原理"

Posted by Xu on January 17, 2018

rsync工作原理和在迁移上的应用分析

rsync可以实现对源端到目的端的文件同步,当源端文件发生修改时,可以利用增量传输的方式来同步两端文件的内容,这对于在热迁移过程中的文件系统同步有着很关键的作用,因为每一次的前一迭代都涉及到可读写层的同步更新。今天我们来具体了解一下rsync这个命令的实现原理,并结合我们的迁移工作来做相关分析。

rsync算法原理

首先我们对rsync同步原理做一个总体的场景概括:

假设我们需要将文件F从A主机同步到B主机:

  • 该算法第一步使用quick check算法来决定该文件是否需要传输,quick check算法会比较源文件和目的文件的文件大小及修改时间mtime,如果不同说明该文件需要传输
  • 当quick check算法发现文件A需要传输后,会分析源端和目的端经过三次匹配检测后,将匹配信息及要传输的增量数据发送到目的端B
  • 目的端B接收到匹配信息及有所区别的增量数据后,会建立一个临时文件对该文件的数据进行重组。重组完成后利用rename操作将该文件移动到对应目录
  • 最后源端A发送一个整个文件级的校验码到B端进行匹配,若匹配成功说明增量数据传输成功

算法实现细节

假设要将文件Fa中的内容”123xxabc def”从源端A同步到目的端B中指定目录下的文件Fb,目的端B文件F的内容为”123abcdefg”.

现在源端A为发送端sender,目的端B为receiver。将文件Fa从A同步到B的Fb时候,需要经历如下6个过程:

rsync

  1. A 主机告诉B主机文件Fa待传输
  2. B 主机收到消息后,将文件Fb划分为一系列大小固定的数据块(一般大小建议在500-1000字节),并以chunk号码对数据块进行编号,同时还会记录数据块的起始偏移地址和数据块的长度。为了方便讲解,我们设置数据块的大小为3,所以Fb划分后的数据块如下:
    count=4 n=3 rem=1    这表示划分了4个数据块,数据块大小为3字节,剩余1字节给了最后一个数据块
    chunk[0]:offset=0 len=3 该数据块对应的内容为123
    chunk[1]:offset=3 len=3 该数据块对应的内容为abc
    chunk[2]:offset=6 len=3 该数据块对应的内容为def
    chunk[3]:offset=9 len=1 该数据块对应的内容为g
    
  3. B主机对每个数据块根据内容计算两个校验码:32位弱滚动校验码rolling checksum和128位的MD4强校验码:(其中sum1为rolling checksum,sum2为强校验码。)
    chunk[0] sum1=3ef2c827 sum2=3efa923f8f2e7
    chunk[1] sum1=57ac2aaf sum2=aef2dedba2314
    chunk[2] sum1=92d7edb4 sum2=a6sd6a9d67a12
    chunk[3] sum1=afe74939 sum2=90a12dfe7485c
    
  4. 当A主机接收到B主机发送来的文件Fb的校验码集合后,对每个rolling checksum计算16位长度的hash值,并将每216个hash值放入到一个hash表中,与对应的chunk号码进行连接,并进行排序。 hash
  5. 主机A对文件Fa进行处理同样取相同大小数据块计算校验码,并与传送过来的校验码集合进行匹配:匹配过程主要有三步,hash比较-》rolling checksum比较-》强校验码MD5比较。

    • 若匹配成功,则不需要传输,主机A直接跳转到该数据块末端进行下一轮匹配。
    • 若匹配失败,则移到到下一个字节重新进行匹配

如果划分的数据块太小,会影响该算法性能,数据块太大,造成很多数据块无法匹配传输的冗余数据就增多,所以可以利用-B(–block-size)来调整数据块大小,一般建议在500-1000字节

6. 当A主机发现匹配块时会发送该匹配块的附加信息给B主机,非匹配数据也会发送到B主机,B主机接收到这些数据后会创建一个临时文件,对新文件进行重组,那些匹配成功没有传送过来的数据会从B主机本地的文件Fb中拷贝。最后对该临时文件进行重命名操作替换指定目录的文件。B主机收到的数据信息为:

chunk[0] of size 3 at 0 offset=0(匹配的数据附加信息,size为匹配数据的大小,at表示在原文件中的偏移量,offset表示在新重组文件中的偏移量:"123",该数据会在B主机本地进行拷贝)
data receive 2 at 3(非匹配的纯数据:“xx”)
chunk[1] of size 3 at 3 offset=5("abc")
data receive 1 at 8(非匹配的纯数据:“ ”)
chunk[2] of size 3 at 6 offset=9("def")

7. 数据重组结束后,A主机会计算整个文件的一个强校验码发送给B,B也会计算重组后文件的强校验码,进行匹配,匹配成功则说明数据增量传输成功。

总结rsync的使用场景

1. rsync不适合对大文件进行实时同步。

从前文中已经知道,rsync的sender端因为要计算比较校验码而对cpu的消耗很高,receiver端因为要从basis file中复制数据而对io的消耗很高。

像数据库文件这样的大文件,且是频繁访问的文件,如果使用rsync实时同步,sender端还好,但是receiver端肯定扛不住巨大的io压力,再好的机器也扛不住。因为每增量同步一次,receiver端都要从巨大的basis file(一般提供服务的数据库文件至少都几十G)中复制一次,相当于是在receiver端直接cp了一个数据库文件,如果是频繁同步,receiver就会频繁复制basis file,它的io一定会爆的。

所以,对频繁改变的单个大文件只适合用rsync偶尔同步一次,也就是备份的功能,它不适合实时同步。像数据库文件,要实时同步应该使用replication功能。

2. 可以使用rsync对大量小文件进行实时同步。

由于rsync是增量同步,所以对于receiver端已经存在的和sender端相同的文件,sender端是不会发送的,这样就使得sender端和receiver端都只需要处理少量的文件,由于文件小,所以无论是sender端的cpu还是receiver端的io都不是问题。

但是,rsync的实时同步功能是借助工具来实现的,如inotify+rsync,sersync,所以这些工具要设置合理,否则实时同步一样效率低下,不过这不是rsync导致的效率低,而是这样工具配置的问题。