1、引言
基于LAN或WAN的网络应用之间进行数据传输或者同步非常普遍,比如远程数据镜像、备份、复制、同步,数据下载、上传、共享等等,最为简单的做法自然就是对数据进行完全复制。然而,数据在网络上来回被复制多次后就会存在大量副本,很多情形下这些文件副本之间仅有很小的差异,很可能是从同一个文件版本演化而来。如果对文件进行完全复制,在文件较大的情况下,会占用大量网络带宽,同步时间也会较长。目前,广域网WAN的带宽与访问延迟仍然是急需解决的问题,完全复制使得很多网络应用无法提供良好的服务质量,比如分布式文件系统(DFS)、云存储(Cloud Storage)。Rsync与RDC(Remote Differential Compression)是两种最为常见的数据同步算法,它们仅传输差异数据,从而节省网络带宽并提高效率。本文基于这两种算法思想并借助重复数据删除(De-duplication)技术,对数据同步算法进行深入研究与分析,并研发了原型系统。首先介绍rsync与RDC算法,然后详细描述算法设计与相应的数据结构,并重点分析文件分块、差异编码、文件同步算法,最后简介推拉两种应用模式。
2、相关工作
Rsync是类Unix环境下的一个高效的远程文件复制(同步)工具,它通过著名的Rsync算法来优化流程,减少了数据通信量并提高文件传输效率。假设现在有两台计算机Alpha和Beta ,计算机Alpha能够访问A文件,计算机Beta能够访问B文件,文件A和B非常相似,计算机Alpha和Beta通过低速网络互联。它的大致流程如下(详细过程请参考Rsync作者Andrew Tridgell的tech_report.ps):
1、Beta将文件B分割成连续不重叠的固定大小数据块S,最后一个数据块上可能会小于S字节;
2、Beta对于每一个数据块,计算出两个校验值,一个32位的弱滚动校验和一个128位的MD4校验;
3、Beta将校验值发送给Alpha;
4、Alpha通过搜索文件A的所有大小为S的数据块(偏移量可以任意,不一定非要是S的倍数),来寻找与文件B的某一块有着相同的弱校验码和强校验码的数据块。这主要由滚动校验Rolling checksum快速完成;
5、Alpha给Beta发送重构A文件的指令,每一条指令是一个文件B数据块引用(匹配)或者是文件A数据块(未匹配)。
Rsync是一个非常优秀的工具,但它仍然存在一些不足之处。
1、Rolling checksum虽然可以节省大量checksum校验计算量,也对checksum搜索作了优化,但多出一倍以上的hash查找,这个消耗不小;
2、Rsync算法中,Alpha和Beta计算量是不对等的,Alpha计算量非常大,而Bete计算量非常小。通常Alpha是服务器,因此压力较大;
3、Rsync中数据块大小是固定的,对数据变化的适应能力有限。
RDC算法的典型代表是微软DFS中的DFSR(Distributed File System Replication),它与Rsync不同之处在于采用一致的分块规则对复制的源文件和目标文件进行切分。因此,RDC对于源端和目标端的计算量是对等的。RDC和RSync算法在设重点上有所不同,Rsync追求更高的重复数据发现而不惜计算量;RDC在两者之间作了一个折衷,目标是以少量的计算快速发现数据差异,当然重复数据发现不及Rsync。另外,Rsync是定长分块策略,而RDC是变长分块策略。
3、重复数据删除技术
De-duplication,即重复数据删除,它是一种非常新的且流行度很高的存储技术,可以大大减少数据的数量。重复数据删除技术,通过数据集中重复的数据,从而消除冗余数据。借助dedup技术,可以提高存储系统的效率,有效节约成本、减少传输过程中的网络带宽。同时它也是一种绿色存储技术,能有效降低能耗。
Dedupe按照消重的粒度可以分为文件级和数据块级。文件级的dedup技术也称为单一实例存储(SIS, Single Instance Store),数据块级的重复数据删除,其消重粒度更小,可以达到4-24KB之间。显然,数据块级的可以提供更高的数据消重率,因此目前主流的 dedup产品都是数据块级的。将文件都分割成数据块(定长或变长的数据块),采用MD5或SHA1等Hash算法 (可以同时使用两种或以上hash算法或CRC校验等,以获得非常小概率的数据碰撞发生)为数据块计算指纹(FP, Fingerprint)。具有相同FP指纹的数据块即可认为是相同的数据块,存储系统中仅需要保留一份。这样,一个物理文件在存储系统就对应一个逻辑表示,由一组FP组成的元数据。当进行读取文件时,先读取逻辑文件,然后根据FP序列,从存储系统中取出相应数据块,还原物理文件副本。
Dedupe技术目前主要应用于数据备份,因此对数据进行多次备份后,存在大量重复数据,非常适合这种技术。事实上,dedupe技术可以用于很多场合,包括在线数据、近线数据、离线数据存储系统,甚至可以在文件系统、卷管理器、NAS、SAN中实施。也可以用于网络数据传输,当然也可以应用于数据打包技术。Dedupe技术可以帮助众多应用降低数据存储量,节省网络带宽,提高存储效率、减小备份窗口,绿色节能。
4、数据同步算法
如Rsync假设现在有两台计算机Alpha和Beta ,计算机Alpha能够访问A文件,计算机Beta能够访问B文件,文件A和B非常相似,计算机Alpha和Beta通过低速网络互联。基于dedupe技术的数据同步算法大致流程与Rsync相似,简单描述如下:
1、Beta采用数据切分算法,如FSP(fixed-size partition)、CDC(content-defined chuking),将文件B分割成大小相等或不等的数据块;
2、Beta对于每一个数据块,计算一个类似rsync弱校验值和md5强校验值,并记录数据块长度len和在文件B中的偏移量offset;
3、Beta将这将数据块信息发送给Alpha;
4、Alpha采用同样的数据块切分技术将文件A切成大小相等或不等的数据块,并与Beta发过来的数据信息进行搜索匹配,生成差异编码信息;
5、Alpha将差异编码信息发送给Beta,并同时发送重构文件A的指令;
6、Beta根据差异编码信息和文件B重构文件A。
上面算法描述中,有几个关键问题需要解决,即文件切分、切分数据块信息描述、差异编码、差异编码信息描述、文件同步。文件切分、差异编码、文件同步将在后续部分介绍,这里对切分数据块信息描述和差异编码信息描述作说明。
切分数据块信息的数据文件布局由文件头(chunk_file_header)和数据块描述(chunk_block_entry)实体集组成,具体定义如下。其中,文件头定义了文件B的数据块大小、数据块总数。文件头后紧随一组数据块描述实体,每个实体代表一个数据块,定义了块长度、块在文件B中的偏移、弱校验值和强md5校验值。
/* define chunk file header and block entry */
typedef struct _chunk_file_header {
uint32_t block_sz;
uint32_t block_nr;
} chunk_file_header;
#define CHUNK_FILE_HEADER_SZ (sizeof(chunk_file_header))
typedef struct _chunk_block_entry {
uint64_t offset;
uint32_t len;
uint8_t md5[16 + 1];
uint8_t csum[10 + 1];
} chunk_block_entry;
#define CHUNK_BLOCK_ENTRY_SZ (sizeof(chunk_block_entry))
差异编码信息的数据文件布局同样由文件头(delta_file_header)和数据块描述实体(delta_block_entry)集组成,如下所定义。其中,文件头定义了文件A的数据块总数、最后一个数据的长度和偏移。文件头后紧随一组数据块描述实体,每个实体代表一个数据块,定义了数据块长度、偏移以及数据块位置指示。如果embeded为1,则表示数据块位于差异编码文件中offset处,数据紧随该实体后;如果embeded为0,则表示数据块位于文件B中offset处。最后数据块存储于差异编码文件尾部,长度和偏移由头部指示。
/* define delta file header and block entry */
typedef struct _delta_file_header {
uint32_t block_nr;
uint32_t last_block_sz;
uint64_t last_block_offset; /* offset in delta file */
} delta_file_header;
#define DELTA_FILE_HEADER_SZ (sizeof(delta_file_header))
typedef struct _delta_block_entry {
uint64_t offset;
uint32_t len;
uint8_t embeded; /* 1, block in delta file; 0, block in source file. */
} delta_block_entry;
#define DELTA_BLOCK_ENTRY_SZ (sizeof(delta_block_entry))
从实时性能方面考虑,数据块信息和差异编码信息并不一定要写入文件,可以存在于Cache中,但数据布局与上面描述相同。
5、文件切分
Dedupe技术中,数据分块算法主要有三种,即定长切分(fixed-size partition)、CDC切分(content-defined chunking)和滑动块(sliding
block)切分。定长分块算法采用预先定义好的块大小对文件进行切分,并进行弱校验值和md5强校验值。弱校验值主要是为了提升差异编码的性能,先计算弱校验值并进行hash查找,如果发现则计算md5强校验值并作进一步hash查找。由于弱校验值计算量要比md5小很多,因此可以有效提高编码性能。定长分块算法的优点是简单、性能高,但它对数据插入和删除非常敏感,处理十分低效,不能根据内容变化作调整和优化。
CDC算法是一种变长分块算法,它应用数据指纹(如Rabin指纹)将文件分割成长度大小不等的分块策略。与定长分块算法不同,它是基于文件内容进行数据块切分的,因此数据块大小是可变化的。算法执行过程中,CDC使用一个固定大小(如48字节)的滑动窗口对文件数据计算数据指纹。如果指纹满足某个条件,如当它的值模特定的整数等于预先设定的数时,则把窗口位置作为块的边界。CDC算法可能会出现病态现象,即指纹条件不能满足,块边界不能确定,导致数据块过大。实现中可以对数据块的大小进行限定,设定上下限,解决这种问题。CDC算法对文件内容变化不敏感,插入或删除数据只会影响到检少的数据块,其余数据块不受影响。CDC算法也是有缺陷的,数据块大小的确定比较困难,粒度太细则开销太大,粒度过粗则dedup效果不佳。如何两者之间权衡折衷,这是一个难点。
滑动块算法结合了定长切分和CDC切分的优点,块大小固定。它对定长数据块先计算弱校验值,如果匹配则再计算md5强校验值,两者都匹配则认为是一个数据块边界。该数据块前面的数据碎片也是一个数据块,它是不定长的。如果滑动窗口移过一个块大小的距离仍无法匹配,则也认定为一个数据块边界。滑动块算法对插入和删除问题处理非常高效,并且能够检测到比CDC更多的冗余数据,它的不足是容易产生数据碎片。
6、差异编码
差异编码的基础是文件B数据分块信息和文件A,它首先对文件A进行对等数据分块(滑动块算法除外,它对文件B的切分是定长算法,而对文件A是滑动块算法),然后匹配文件B数据分块信息。如果数据块匹配,则用数据块索引表示,达到重复数据删除效果。否则,则将对应的文件A数据块写入差异编码文件中。数据块匹配算法方面,定长切分和CDC切分是基本相同,文件A采用和文件B对等的切分算法进行数据块切分。滑动块算法与其他两种算法不同,它与rsync类似,它对文件B的切分是定长算法,而对文件A的切分是滑动块算法。因此,这种算法切分是不对等的。然后根据文件B构造hashtable,通过hash查找进行匹配,并按照差异编码数据布局构造相应数据文件。
7、文件同步
Beta得到差异编码文件delta,再结合已有的文件B,即可以将文件B同步成文件A的副本。同步算法遍历delta文件,读取每一个数据块描述实体,根据embeded标志分别从delta和文件B中读取相应的数据块,重新构造出文件A。
8、PULL与PUSH模式
数据同步有PULL和PUSH两种应用模式,PULL是将远程数据同步到本地,而PUSH是将本地数据同步到远程。对应到同步算法,主要区别在于数据分块和差异编码位置不同。PULL和PUSH同步模式步骤分别如下所述。
PULL同步模式流程:
1、本地对文件A进行数据切分,生成数据块描述文件chunk;
2、上传chunk文件至远程服务器;
3、远程服务器对文件B进行差异编码,生成差异编码文件delta;
4、下载delta文件至本地;
5、本地同步文件A至文件B,相当于下载文件B到本地文件A。
PUSH同步模式流程:
1、远程服务器对文件B进行数据切分,生成数据块描述文件chunk;
2、下载chunk文件至本地;
3、本地对文件A进行差异编码,生成差异编码文件delta;
4、上传delta文件至远程服务器;
5、远程同步文件B到A,相当于上传文件A到远程文件B。