Incremental Synchronization

来源:互联网 发布:日本网络直播网站 编辑:程序博客网 时间:2024/05/14 04:30
微信大家都用。作为一个IM工具,有个小功能,就是当你离线了一段时间后,重新连接,你错过的一些消息会重新接收到,那么,这部分错过的消息的接收,就是一种incremental synchronization.

同样的,当你在使用Google Doc时,或者使用在线WPS时,编辑操作也是增量式的接收的。当你在线时,peer的编辑操作会同步到本地,而当你离线后,peer的编辑操作继续,但你是无法接受到的;当你重新连线后,错过的那部分编辑操作会被接收,以确保本地的版本与peer是同步的。

这个功能是怎么实现的呢?很显然,需要引入一个概念,就是revision log. 每一个操作都对应一个revision,revision是顺序递增的。peer需要维护本地的最新revision,当进行incremental sync时,通过本地的revision,向后台请求delta revision log。所谓revision log,即是指后台将所有的操作都储存下来作为log。需要指出的是,对于微信这种IM工具而言,消息本身就是revision log,而后台的服务器存储的最终数据,也是消息本身。但是,对于Google Doc或者在线版的WPS而言,编辑操作本身就是revision log,但是,后台服务器存储的最终数据,是文件的数据。换句话讲,对于文档编辑而言,后台服务器存储了两套数据,一套是文档的当前数据(instant data),一套是文档的编辑操作的历史数据(revision log)。

revision是顺序递增的。这一点很重要。显然,服务器端作为将peer的并发的编辑操作串行化的地点,只有服务器端才能够正确的更新revision。

看到这里,读者觉着,incremental sync不过如此。

但是,对于文档编辑这种产品,难点并不在于revision的引入和存储log可能的大数据量的处理,而在于后台的client加载instant data与确认当前revision的对应关系。

试想,当用户打开一个文档文件时,从instant data读取文档数据。但是,instant data是即时的,在用户加载文档数据的过程中,peer完全有可能正在对数据进行更改。在这种情况下,用户无法保证加载的数据是对应于一个revision。完全有可能,一个文档文件被加载后,前100行对应revision 100, 而后100行对应revision 101.

基于经典数据库的理论,其实这是一个再常见不过的ACID问题。支持transaction的数据库,可以解决这个问题。但是,在分布式环境下,distributed transaction 是一个非常重量级的功能,开销巨大。开发者也可以考虑optimistic locking

写到这里,基本的要点就算结束了。接下来,还有些小细节可以指出。

对于文档编辑类工具,编辑操作有可能会很大。譬如说,删除一个子文档或者工作表,然后进行undo(撤销)。撤销操作将新建一个子文档或者工作表,并且数据与删除前一样。在单机情况下,这种操作时很好处理的(本地存储可以做缓存)。但是在协同编辑的情况下,考虑场景:Step1.peerA delete工作表1;Step2. peer B加载文档,开始协同编辑。Step3. peerA执行撤销。对于peerB而言,他需要在本地恢复出工作表1,但是,显然,peerB的本地时没有工作表1的数据的。peerB完全依赖于同步的编辑操作。显然,该同步而来的编辑操作是不适合携带工作表1的数据的。

那么,该如何同步这种类型的操作呢?开动脑筋吧!(提示一下,无论如何,后台数据库里拥有这个工作表1的instant data)

以上谈的都是增量同步当中的一个方向,就是incremental download。在另一个方向上,则变成了incremental upload。无论是incremental download还是incremental upload,都涉及到基于Operational Transformation的intention preservation。但是,upload与download在技术上存在一些区别。对于download而言,因为下载的是来自服务器的操作数据,而服务器的操作数据是权威的数据,所有服务器的操作都拥有唯一的revision。所以,完全可以在incremental download的实现中,一个操作一个操作的下载到本地并同步,而在这个同步过程中是不需要握手或者ACK的。但是,当要把本地的操作同步到服务器时(incremental upload),本地的操作是temporary的操作,需要发到服务器,由服务器基于Operational Transformation,确定操作的最终形式和内容,所以,incremental upload是需要握手或者ACK的。正是因为这个区别,倒是incremental upload 和 incremental download 在效率方面可能存在较大的差异。因为Operational Transformation技术天然的是基于一个原子的操作的,所以在incremental upload过程中的握手或者ACK也是单一操作这个粒度的。可以想象,在incremental upload需要上载较多操作数据的情况下,握手或者ACK的开销是很大的。

显然,为了避免这种不必要的开销,我们需要将操作进行打包,或者说是融合,尽量减少incremental upload过程中的握手次数,举例而言,如果本地有三个修改单元格的操作,那么,可以将三个操作融合成一个修改单元格的操作,再向后台upload,这样可以避免多余的upload握手,我们称这样的优化为Fusion。另一方面,在下文讲到复合操作时,也会对该问题有所启发。

原创粉丝点击