我觉得必须有客户端 - 服务器同步模式.但我完全没有谷歌一个.
情况非常简单 - 服务器是中心节点,多个客户端连接并操作相同的数据.数据可以在原子中分割,如果发生冲突,服务器上的任何内容都具有优先级(以避免让用户解决冲突).由于可能存在大量数据,因此首选部分同步.
对于这种情况是否存在任何模式/良好实践,或者如果您不知道 - 您的方法是什么?
以下是我现在想要解决的问题:与数据并行,将保留修改日志,使所有交易都有时间戳.当客户端连接时,它会以统一的形式接收自上次检查以来的所有更改(服务器遍历列表并删除添加后跟随删除,合并每个原子的更新等).瞧,我们是最新的.
备选方案是保留每条记录的修改日期,而不是执行数据删除,只需将它们标记为已删除即可.
有什么想法吗?
您应该了解分布式变更管理的工作原理.查看管理增量工作的SVN,CVS和其他存储库.
你有几个用例.
同步更改.您的更改日志(或增量历史记录)方法看起来很好.客户端将其增量发送到服务器; 服务器整合并将增量分配给客户端.这是典型的情况.数据库称之为"事务复制".
客户端已失去同步.通过备份/恢复或由于错误.在这种情况下,客户端需要从服务器获取当前状态而不通过增量.这是从大师到细节,三角洲和表现的副本.这是一次性的事情; 客户坏了; 不要试图优化这一点,只需实现可靠的副本.
客户很可疑.在这种情况下,您需要将客户端与服务器进行比较,以确定客户端是否是最新的并且需要任何增量.
您应该遵循数据库(和SVN)设计模式,按顺序编号每个更改.这样,客户端在尝试同步之前可以提出一个简单的请求("我应该有什么修订?").即便如此,查询("自2149年以来的所有增量")对于客户端和服务器来说都是非常简单的.
作为团队的一员,我做了很多涉及数据同步的项目,所以我应该有能力回答这个问题.
数据同步是一个相当广泛的概念,有太多的讨论方法.它涵盖了一系列不同的方法,包括它们的优点和缺点.以下是基于两个视角的可能分类之一:同步/异步,客户端/服务器/点对点.同步实施严重依赖于这些因素,数据模型复杂性,传输和存储的数据量以及其他要求.因此,在每种特定情况下,选择应该支持满足应用程序要求的最简单实现.
基于对现有现成解决方案的回顾,我们可以描述几个主要的同步类,不同的是同步对象的粒度:
整个文档或数据库的同步用于基于云的应用程序,例如Dropbox,Google Drive或Yandex.Disk.当用户编辑并保存文件时,新文件版本将完全上载到云端,覆盖较早的副本.如果发生冲突,则会保存两个文件版本,以便用户可以选择哪个版本更相关.
键值对的同步可以在具有简单数据结构的应用程序中使用,其中变量被认为是原子的,即不分成逻辑组件.此选项类似于同步整个文档,因为值和文档都可以完全覆盖.但是,从用户的角度来看,文档是由许多部分组成的复杂对象,但键值对只是短字符串或数字.因此,在这种情况下,我们可以使用更简单的冲突解决策略,考虑到更相关的价值,如果它是最后一个改变的话.
结构化为树或图的数据的同步用于更复杂的应用程序,其中数据量足够大以在每次更新时完整地发送数据库.在这种情况下,必须在单个对象,字段或关系的级别上解决冲突.我们主要关注这个选项.
所以,我们把这些知识运用到了这篇文章中,我认为对于这个主题感兴趣的人可能非常有用=>基于核心数据的iOS应用程序中的数据同步(http://blog.denivip.ru/index.php/2014/04/data-syncing-in-core-data-based-ios-apps /?lang = en)
你真正需要的是操作变换(OT).在许多情况下,这甚至可以迎合冲突.
这仍然是一个活跃的研究领域,但有各种OT算法的实现.我已经参与了这样的研究多年了,所以请告诉我这条路线是否让您感兴趣,我很乐意为您提供相关资源.
问题不是很清楚,但如果我是你,我会考虑乐观锁定.它可以使用服务器为每条记录返回的序列号来实现.当客户端尝试保存记录时,它将包含从服务器接收的序列号.如果序列号与接收到更新时数据库中的序列号匹配,则允许更新并且序列号递增.如果序列号不匹配,则不允许更新.
大约8年前,我为一个应用程序构建了这样的系统,我可以分享随着应用程序使用率的增长而演变的几种方式。
我首先将任何设备的所有更改(插入,更新或删除)记录到“历史记录”表中。因此,例如,如果有人在“联系人”表中更改了他们的电话号码,则系统将编辑contact.phone字段,并添加具有action = update,field = phone,record = [contact ID],值= [新电话号码]。然后,每当设备同步时,它都会下载自上次同步以来的历史记录项,并将其应用于其本地数据库。这听起来像上述的“事务复制”模式。
一个问题是,当可以在不同设备上创建项目时,保持ID唯一。我刚开始时并不了解UUID,所以我使用了自动递增的ID,并编写了一些复杂的代码,这些代码在中央服务器上运行,以检查从设备上传的新ID,如果发生冲突则将其更改为唯一ID,并且告诉源设备更改其本地数据库中的ID。只需更改新记录的ID并没有那么糟,但是,例如,如果我在联系人表中创建了一个新项目,然后在事件表中创建了一个新的相关项目,那么现在我也需要使用外键检查并更新。
最终,我了解到UUID可以避免这种情况,但是到那时我的数据库已经变得很大,而且我担心完整的UUID实施会造成性能问题。因此,我没有使用完整的UUID,而是开始使用随机生成的8个字符的字母数字键作为ID,并且将现有代码保留在适当的位置以处理冲突。在我当前的8个字符的键和UUID的36个字符之间的某个位置,必须有一个甜点,可以消除冲突而不会造成不必要的膨胀,但是由于我已经有了冲突解决代码,因此尝试该冲突并不是优先考虑的事情。 。
下一个问题是,历史表的大小大约是数据库其余部分的10倍。这使存储变得昂贵,并且对历史表的任何维护都可能很麻烦。保留整个表可以使用户回滚以前的任何更改,但是开始感觉有些过时了。因此,我在同步过程中添加了一个例程,在该过程中,如果历史记录表中不再存在设备上次下载的历史记录项,则服务器不会为其提供最近的历史记录项,而是为其提供一个包含所有数据的文件该帐户。然后,我添加了一个cronjob来删除90天以上的历史记录项。这意味着用户仍可以回滚少于90天的更改,并且如果他们每90天至少同步一次,则更新将像以前一样进行增量。但是如果他们等待超过90天,
所做的更改使历史记录表的大小减少了近90%,因此现在维护历史记录表只会使数据库的大小变成原来的两倍,而不是原来的十倍。该系统的另一个好处是,如果需要,即使没有历史记录表,同步仍然可以进行-就像我需要做一些维护使它暂时脱机一样。或者,我可以为不同价格的帐户提供不同的回滚时间段。如果要下载的更改超过90天,则完整文件通常比增量格式更有效。
如果我今天从头开始,我将跳过ID冲突检查,而只瞄准足以消除冲突的密钥长度,并进行某种错误检查,以防万一。但是历史记录表以及最近更新的增量下载或需要时进行的完整下载的组合一直运行良好。