同步客户端 – 服务器数据库

我正在寻找一些常规策略,用于将中央服务器上的数据与不总是在线的客户端应用程序进行同步。

在我的情况下,我有一个Android手机应用程序与SQLite数据库和PHP Web应用程序与MySQL数据库。

用户将能够在手机应用程序和networking应用程序上添加和编辑信息。 即使手机不能立即与服务器通信,我也需要确保在一个位置进行的更改反映到处都是。

我不关心如何将数据从手机传输到服务器,反之亦然。 我只提到我的特定技术,因为我不能使用例如可用于MySQL的复制function。

我知道客户端 – 服务器数据同步问题已经存在了很长很长的时间,并希望获得关于处理问题的模式的信息(文章,书籍,build议等)。 我想知道处理同步的一般策略,比较长处,弱点和取舍。

首先要决定的是一个一般的政策,哪一方在相互冲突的情况下被认为是“权威的”。

即:假设1月5日晚上10点服务器上的logging#125被更改,并且在1月5日晚上11点,其中一个电话(我们称之为客户端A)的logging被更改。 上一次同步是在1月3日。 然后,用户重新连接,例如1月8日。

从客户端和服务器都知道最后一次同步的date来看,确定需要更改的内容是“容易的”,因此需要协调自上次同步以来创build或更新的任何内容(请参阅下面的更多内容)。

所以,假设唯一改变的logging是#125。 您可以决定两者中的一个自动“胜出”并覆盖另一个,或者您需要支持协调阶段,用户可以决定哪个版本(服务器或客户端)是正确的,覆盖另一个版本。

这个决定是非常重要的,你必须重视客户的“angular色”。 特别是如果不仅客户端和服务器之间存在潜在的冲突,而且如果不同的客户端可以更改相同的logging。

[假设#125可以被第二个客户端(客户端B)修改,客户端B有机会还未提供同一个logging的另一个版本,从而使之前的冲突解决scheme没有任何争议]

关于上面的“ 创build或更新 ”的观点,如果一个logging是来自其中一个客户端(假设在问题域中有意义),那么如何正确识别这个logging呢? 假设您的应用程序pipe理业务联系人列表。 如果客户A说你必须添加一个新创build的John Smith,并且服务器有一个由客户D创build的John Smith …你是否创build了两个logging,因为你不能确定他们不是不同的人? 你是否会要求用户调和这个冲突?

客户是否拥有一部分数据的“所有权”? 即如果客户端B被设置为区域#5的数据的“权威”,客户端A可以修改/创build区域#5的logging吗? (这会使解决冲突更简单,但对您的情况来说可能不可行)。

总结起来主要的问题是:

  • 如何定义“身份”,考虑到分离的客户端在创build新logging之前可能没有访问服务器。
  • 以前的情况,无论解决scheme多么复杂,都可能导致数据重复,所以您必须预见如何定期解决这些问题,以及如何通知客户他们认为“Record#675”实际上已经被合并/取代logging#543
  • 决定是否通过法令解决冲突(例如,如果前者自上次同步后更新,则服务器版本总是胜过客户端)或通过手动干预
  • 法令的情况下,特别是如果您决定优先考虑客户,则还必须考虑如何处理其他尚未同步的客户,这些客户可能会有更多更改。
  • 以前的项目不考虑数据的粒度(为了使描述更简单)。 我只想说,不像在我的例子中那样,在“logging”层面进行推理,你可能会发现在现场级别logging变更更为合适。 或者一次处理一组logging(例如个人logging+地址logging+联系人logging),一次将其集合视为一种“元logging”。

参考书目:

  • 更多关于这个,当然,在维基百科上 。

  • Vdirsyncer的作者简单的同步algorithm

  • OBJC关于数据同步的文章

  • SyncML®:同步和pipe理您的移动数据 (在O'Reilly Safari上预订)

  • 无冲突复制数据types

  • 乐观的复制 YASUSHI SAITO(惠普实验室)和MARC SHAPIRO(微软研究有限公司) – ACM Computing Surveys,Vol。 V,N号,2005年3月。

  • Alexander Traud,Juergen Nagler-Ihlein,Frank Kargl和Michael Weber。 2008.重复使用SyncML循环数据同步。 在第九届国际移动数据pipe理大会(MDM'08)的论文集中。 IEEE计算机协会,华盛顿特区,美国,​​165-172。 DOI = 10.1109 / MDM.2008.10 http://dx.doi.org/10.1109/MDM.2008.10

  • Lam,F.,Lam,N。和Wong,R。2002.移动XML数据的高效同步。 第十一届信息与知识pipe理国际会议论文集(美国弗吉尼亚州麦克莱恩,2002年11月4日 – 09日)。 CIKM '02。 ACM,New York,NY,153-160。 DOI = http://doi.acm.org/10.1145/584792.584820

  • Cunha,PR和Maibaum,TS 1981.资源和设备; 抽象数据types+同步 – 面向消息编程的一种方法。 在第五届软件工程国际会议论文集(美国加利福尼亚州圣迭戈,1981年3月9日至12日)上。 国际软件工程会议。 IEEE Press,Piscataway,NJ,263-272。

(最后三个来自ACM数字图书馆,不知道你是否是会员,或者是否可以通过其他渠道获得)。

从Dr.Dobbs网站:

  • 使用SQL Server CE和SQL RDA创build应用程序作者:Bill Wagner 2004年5月19日(devise桌面和移动PC应用程序的最佳实践 – Windows / .NET)

来自arxiv.org:

  • 无冲突的复制JSON数据types – 本文描述了一个JSON CRDT实现(无冲突复制数据types – CRDT – 是支持并发修改并保证这种并发更新收敛的一系列数据结构)。

我build议您在每个表格中都有一个时间戳列,并且每次插入或更新时都要更新每个受影响行的时间戳记值。 然后,遍历所有表,检查时间戳是否比目标数据库中的时间戳更新。 如果更新,则检查是否需要插入或更新。

观察1:由于从源数据库中删除行,所以要注意物理删除,并且必须在服务器数据库中执行相同的操作。 您可以解决这个问题,避免物理删除或logging与时间戳表中的每个删除。 像这样: DeletedRows = (id, table_name, pk_column, pk_column_value, timestamp)所以,你必须读取DeletedRows表的所有新行,并使用table_name,pk_column和pk_column_value在服务器上执行删除。

观察2:注意FK,因为将数据插入到与另一个表相关的表中可能会失败。 数据同步之前,应该停用每个FK。

如果有人正在处理类似的devise问题,并需要在多个Android设备之间同步更改,我build议您查看Google Cloud Messaging for Android (GCM)。

我正在研究一个解决scheme,在一个客户端上所做的更改必须传播给其他客户端。 我刚刚实现了一个概念validation(服务器和客户端),它的作用就像一个魅力。

基本上,每个客户端发送增量更改到服务器。 例如,资源ID ABCD1234已从值100更改为99。

服务器根据其数据库validation这些增量变化,并批准更改(客户端同步)并更新其数据库或拒绝更改(客户端不同步)。

如果更改通过服务器认可,则服务器通过GCM通知其他客户端(不包括发送增量更改的客户端),并发送携带相同增量更改的组播消息。 客户端处理此消息并更新其数据库。

很酷的事情是,这些变化几乎是瞬间传播! 如果这些设备在线。 而且我不需要在这些客户端上实施任何投票机制。

请记住,如果某个设备的离线时间过长,并且GCM队列中有超过100条消息正在等待传送,则GCM将丢弃这些消息,并在设备重新联机时发送一条特殊消息。 在这种情况下,客户端必须与服务器完全同步。

查看本教程以开始使用CGM客户端。

这回答了使用Xamarin框架的开发人员(请参阅https://stackoverflow.com/questions/40156342/sync-online-offline-data

使用xamarin框架实现这一点的一个非常简单的方法是使用Azure的离线数据同步,因为它允许按需从服务器推送和提取数据。 读取操作在本地完成,写入操作按需推送; 如果networking连接中断,则写操作排队,直到连接恢复,然后执行。

实现相当简单:

1)在azure色的门户创build一个移动应用程序(你可以在这里免费试用https://tryappservice.azure.com/

2)连接你的客户端到移动应用程序。 https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-xamarin-forms-get-started/

3)设置您的本地存储库的代码:

 const string path = "localrepository.db"; //Create our azure mobile app client this.MobileService = new MobileServiceClient("the api address as setup on Mobile app services in azure"); //setup our local sqlite store and initialize a table var repository = new MobileServiceSQLiteStore(path); // initialize a Foo table store.DefineTable<Foo>(); // init repository synchronisation await this.MobileService.SyncContext.InitializeAsync(repository); var fooTable = this.MobileService.GetSyncTable<Foo>(); 

4)然后推和拉你的数据,以确保我们有最新的变化:

 await this.MobileService.SyncContext.PushAsync(); await this.saleItemsTable.PullAsync("allFoos", fooTable.CreateQuery()); 

https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-xamarin-forms-get-started-offline-data/