2

让我们以一个 js“应用程序”为例,它基本上执行 CRUD,因此它创建、更新和删除(不是真的)一些“记录”。

在最基本的情况下,不需要解决此类应用程序中的冲突,因为 DBMS 的 ACID 属性用于消除并发更新(我知道我在这里浏览了大量细节)。当无法模拟更新的串行执行时,可以使用时间戳来确定哪个更新“获胜”。即使这样,客户端也不必担心时间戳,因为它们可以在服务器请求时生成。

但是,如果我们更进一步,让更新在客户端排队一段时间(例如,让应用程序在没有网络连接时工作)然后推送到服务器会怎样?则服务器无法生成时间戳,因为更新推送到服务器的时间与实际执行更新的时间可能相差很大。

在理想的世界中,所有时钟都同步,这不是问题 - 只需在执行更新时在客户端上生成时间戳。但实际上,时间经常偏离“服务器”时间(这被认为是完美的,毕竟,它是我们配置服务器,它会出现什么问题?)或者只是几个小时的错误(可能当你不要设置时区,而是更新系统的时间/日期以匹配)。在这种情况下,人们会怎么做才能解释现实?

也许还有其他解决冲突的方法,可以在这种情况下使用?

4

2 回答 2

4

你的问题有两个方面:

  1. 通过数据库的 ACID 属性使用时间戳在服务器上同步/序列化。
  2. 与客户端一起的队列(服务器不知道的延迟)。

如果您在客户端维护队列,当它认为合适时推送到服务器,那么最好进行简单的同步。因为它只是破坏了服务器所依赖的时间戳的目的。

ACID 的范围在这里受到限制,因为如果客户端更新不是实时的,它就无法根据创建的请求的时间戳或请求到达的时间戳进行序列化。它创建了一个场景,其中在请求 R1 之后创建的请求 R2 在 R1 之前到达。

时间是一个相对概念,客户端或服务器使用本地时间会导致drift另一个。它也无法扩展(如果您有多个对等节点 - 分布式,则效率低下)。它引入了单点故障。

为了解决这个问题,设计了矢量时钟。它们是逻辑时钟,当机器上发生事件时自动增加时钟。BASE 数据库(基本可用、软状态、最终一致性)使用它。

结果是 1 和 2 永远不会成功。您永远不应该将使用时间戳来解决冲突的请求排队。

于 2013-09-04T12:01:42.413 回答
1

不错的挑战。虽然我很欣赏user568109的答案,但这就是我在 CQRS/DDD 应用程序中处理类似情况的方式。

虽然在 DDD 应用程序中我有很多不同的命令和查询,但在 CRUD 应用程序中,对于每种类型的“记录”,我们都有 CREATE、UPDATE 和 DELETE 命令以及一个 READ 查询。

在我的系统中,在客户端上,我在一个包含以下内容的元组中跟踪先前的同步:服务器上的 UTC 时间,客户端上的时间(我们称之为LastSync)。

READ
读取查询不会参与同步。不过,在某些情况下,您可能必须向服务器发送 LogRead 命令来跟踪用于做出决策的信息。此类命令确实包含实体的类型、实体的标识符和 LastSync.ServerTime)。

CREATE
创建命令根据定义是幂等的:它们要么成功要么失败(当已经存在具有相同标识的记录时)。在同步时,您将不得不通知用户冲突(以便他可以处理这种情况,例如通过更改标识符)或修复时间戳,如下所述。

UPDATE
更新命令有点棘手,因为您可能应该在不同类型的记录上以不同方式处理它们。为简单起见,您应该能够强制用户最后一次更新总是获胜,并将命令设计为只携带应该更新的属性(就像 SQL UPDATE 语句一样)。否则,您将不得不处理自动/手动合并(但相信我,这是一场噩梦:大多数用户永远不会理解它!)最初我的客户要求大多数实体使用此功能,但过了一段时间他们接受了最后一个更新获胜以避免这种复杂性。此外,如果对已删除对象进行更新,您应该将情况通知用户,并根据更新的实体类型,应用更新或不应用更新。

DELETE 删除
命令应该很简单,除非您必须通知用户发生了可能导致他保留记录而不是删除记录的更新。

您应该仔细分析如何为每种类型的实体处理此命令(并且在更新的情况下,您可能被迫针对要更新的不同属性集以不同方式处理它们)。

SYNC PROCESS
同步会话应该开始向服务器发送一条消息

  • 客户端当前时间
  • 最后同步

这样,服务器可以计算其时间和客户端时间之间的偏移量,并将这种偏移量应用于他收到的每个命令。此外,它可以检查在LastSync之后偏移量是否发生了变化,并选择一种策略来处理这种变化。请注意,这样一来,服务器将不知道客户端的时钟何时被调整。

在成功同步结束时(由您决定成功的含义),客户端将更新LastSync元组。

最后一点
这是一个相当复杂的解决方案。在开始实施之前,您应该与客户仔细考虑这种复杂性是否能给您足够的价值。

于 2013-09-10T10:33:30.607 回答