WawaKM的随笔同步技术分析
数据同步已经有了好多相关的技术了,SyncML,MS Offline Application Block,Google Gears,VSS还有Dataset的离线更新,可是考察了半天这些技术都只适合特定的场景,不能解决WawaKM随笔同步的需求,所以还得自己设计一套同步方案。我们在设计同步方案的时候要考虑尽量的减少网络流量,防止数据丢失,以及数据冲突时采取适当的措施,发这帖子的目的时让大家和我一起考虑一种适合的方案。
- SyncML:目前是用来在移动设备之间或者移动设备和PC之间同步日历、邮件、通讯录,Todolist等,为了减少流量,可使用WBXML来描述数据,支持双向同步,慢同步等多种同步模式,关键是这东西没有随笔这个概念,要同步随笔还得考虑设计一套XML模式,而且还得假设SyncML服务器,我看了半天觉得有些复杂,只是里面的思路有的可以借鉴一下。
- Offline Application Block:有两种同步模式,一种是基于数据复制的,一种是基于面向服务的,前者在本地数据库维护对数据库的修改,联机时用复制功能向服务器将更改传给服务器,关键是这种复制功能需要本地数据库支持(我猜得)。后者是把本地向服务器的请求压入堆栈,在联机的时候集中发给服务器,有点类似命令模式,但这种方式也只适合同步分散、独立的任务,和随笔这里的双向同步需求不太一样,关于何时使用脱机操作可以看这个链接:http://www.microsoft.com/china/msdn/library/architecture/architecture/architecturetopic/Scdnpagoffline_ch01.mspx#EUG
- Google Gears:没有太仔细研究,感觉就Google reader的应用来看,他只是把网络上的数据缓存到本地支持离线看而已,没有本地同步到网络,网络同步到本地以及冲突检测等功能。
- VSS:VSS的这种模式每次用的时候必须得连上服务器,在脱机情况下编辑了本地的数据,签入的时候会出错。其实我也觉得WawaKM的随笔特别类似一个源码管理工具,可又觉得两头都是自己用,如果在办公室锁定了一个随笔,在家里自己也没法编辑的话有些不太合理。
- Dataset:DataSet的脱机更新一种是用时间戳,一种是用特别长的where语句来实现的。不过前提是先要获取整个数据集体,而且update的时候要把整个数据集传给服务器,数据量有些大。但是其中的一些处理逻辑值得细看一下。
随笔同步这里的需求大致如下:
- 我在办公室对随笔进行修改、删除和添加,下班前进行同步操作,回家后,我可以把这些修改后的随笔同步到家里的电脑。
- 我把网络上的随笔同步到本地的时候只下载和本地不同的随笔就可以了,不需要完全的都下载一遍(就是不要SyncML的慢同步)
- 不需要自动的每隔几分钟就自动进行同步,我只需要定时的自动保存内存中对随笔的修改就可以了,我只需要在下班前点一下同步按钮,就会把所有本地需要同步到网络上的随笔同步上去。另外我也可以单独点击某个随笔,把这个随笔的更改同步到网络上,我下班回家看。
- 把网络上的随笔同步到本地的时候,如果这个随笔我在本地编辑过,要提示我。
- 把本地的随笔同步到网络的时候,如果发现网络上的这个随笔被我在其它地方编辑过并同步到了服务器,要提示我。
- 如果我在本地修改了个随笔,同步到网络上的时候,发现这个随笔已经被我在其它地方删除了,要提示我。
- 如果我在本地删除了一个随笔,同步到网络上的时候,发现该随笔比我本地的当时获取的版本有所更新,要提示我。
- 除了随笔要同步的话,如果随笔的分类变了,也要同步,随笔分类的同步和随笔的同步逻辑一样,也要进行冲突检查
下面是我大概的思路
Client到Server的同步
- 新添加Essay的时候OldVersion为0,NewVersion也为0,Client同步到Server的时候,如果Essay的State是IsNew,Server直接inert一个新的Essay就行了其中Essay的ID是guid类型,由Client生成。
- 修改Essay的时候OldVersion为本地数据库的缓存版本,而NewVersion的值是以下面的逻辑生成的。如果NeedSync为true,NewVersion不变,否则NewVersion为OldVersion+1。因为如果在脱机情况下编辑了一个Essay,自动保存后它的NeedSync就会变成true,NewVersion就会变成OldVersion+1,如果又在本地编辑了一下,版本号就没必要+1了。这时候Client同步到Server的时候,Server一看Essay的state为IsEdit,就通过Essay的ID检索出这个Essay,对比一下OldVersion,如果相同,表示Client从Server获取这条essay后没有Server这边没有更改过,Server直接update这个essay where id=@id。如果Client的OldVersion和Server的OldVersion不相同,就会记录一条错误日志,并把Server的Essay副本返回给Client,让用户确认操作,因为这表示Client获取这个Essay后,用户在其它客户端修改后又进行过Client到Server的同步,就是数据冲突了,必须由用户确定一下是保留Server的版本还是保留用户刚刚请求同步的版本。当然了用户进行这次同步请求的时候也许这个Essay很大,不能因为检测出冲突后,用户又选择了强制更新,还需要再把这个Essay发送给服务端一遍,这样太浪费网络流量。服务端检测到数据冲突后用一个hashtable缓存这个已冲突的Essay,key是Essay的ID,如果用户选择了强制更新,请求包里只发送这个要强制更新的Essay的ID就可以了,服务端把hashtable的essay取出来更新到数据库,并把删除hashtable里的那条essay。当然,这个hashtable要每隔一分钟检查一下,删除过时的essay缓存。如果客户端发送强制同步请求,结果哈西表里的essay给删除了,就再次通过协商,让Client上传一下该Essay的信息,呵呵。
- 删除Essay和修改Essay类似,也要进行冲突检测,只是不需要再哈西表里缓存,后续的逻辑是一样的
Server到Client的同步
分析:这部分的设计主要要考虑如何减少网络流量和设计一种数据冲突检测策略。因为服务端不知道客户端的数据和服务端的数据不同的是哪些,又不能一同步就把服务端所有的数据返回给客户端,所以要考虑一种协商策略。开始考虑给所有的Essay加一个时间戳,同步的时候,客户端给服务端一个时间戳,服务端只返回大于这个时间戳的Essay,可是又怕Server和Client的时间不同步,这样就会造成数据丢失。所以最后考虑客户端发送同步请求的时候,把本地的所有Essay检索一下,组成一个essay.id和essay.OldVersion两列的列表,Server接受到后跟服务端的每个essay的version和去比较,把服务端version大于客户端OldVersion的列表返回给客户端,当然这个一条语句不太实现,但要尽量的提高这个过程的性能。如果客户端发送的一个essay在服务端找不到,那么要通知客户端该essay已经删除,是否要删除客户端对应的essay。如果返回给客户端的essay,本地接受后发现该essay已经修改过,就是NeedSync为true,要对客户进行提示是否覆盖本地操作,或者保留本地版本,不知道这样处理好呢,还是在进行Server到client同步之前,先进行Client到Server同步比较好,大家也帮忙考虑一下。
- 智能客户端 Offline Application Block
- 对Smart Client中客户端数据缓存的思考
- WBXML 与 SyncML 服务器的基本需求
- My TT Live
- SyncML 同步协议(SyncML Sync Protocol)
- SyncML技术笔记
- Google Gears
彻底崩溃了,发这个帖子,光调格式调了半小时,累的我一头汗,急的我肚子都疼了。