【问题标题】:Avoiding client/server data synchronization gap避免客户端/服务器数据同步间隙
【发布时间】:2018-03-23 18:37:15
【问题描述】:

我有一个客户端/服务器架构,客户端在连接时执行以下操作:

  • 打开到服务器的套接字并请求更改流(“流”)。
  • 从服务器获取所有数据(“快照”)。

所以这里的想法是快照将在连接点获取客户端所有相关数据,并且流将继续发送更改 - 这样客户端就不必一遍又一遍地进行轮询和获取快照.

这样做的问题是快照和流启动之间存在间隙,这可能导致数据丢失。示例:

  1. 客户端从服务器请求快照和流。
  2. 服务器从数据库中获取快照。
  3. 另一个客户端提交了对 db 的更改(因此快照已过时)。更改将发送到所有流。
  4. 客户端的流已启动。

正如您在上面看到的,客户端最终得到一个过时的快照,并且由于流 init 是异步的,它可能会错过对数据库的更改(它永远不会看到第 3 步中的更改)。

我对如何解决这个问题有一些想法,但到目前为止我对其中任何一个都不满意:

1) 先初始化流,然后获取快照。我不相信这个是安全的,因为这假设流服务器(rabbitmq/kafka/pulsar)不会错过传输中的消息。 2) 让流也推送在连接时间前最后 X 秒内所做的更改。这不是很好,因为它对概率进行时间假设和赌注。

感谢所有输入!

【问题讨论】:

  • 在服务器端可以做什么?例如,您能否枚举更改并让快照包含上次更改的 ID,以便您可以查看是否缺少任何更改并请求?
  • @md2perpe 这实际上是我最终要做的。如何以一种好的方式做到这一点并不明显(仍然没有尝试过),但似乎在更新实体通过流之后使用更新消息的流 id 更新它们似乎是一个万无一失的解决方案到这个。

标签: database asynchronous synchronization client-server message-queue


【解决方案1】:

一些建议:

  1. 让其他人为您处理此问题(例如,使用 Google Cloud Firestore)。
  2. 我不确定这些消息将包含什么,但如果可以使数据库的状态只是流中发送的所有事务消息的总和(即,如果您按时间顺序重播所有消息,则总是以相同的状态结束)然后你可以让服务器给每条消息一个单调递增的 id。当客户端重新连接时,它会告诉服务器它的最大数量,并且服务器会发送所有具有更高 id 的消息。

【讨论】:

  • 谢谢。 1) 不是一个选项。 2)这个解决方案(重播日志)肯定是另一种方法。这将要求我重播整个日志,在我的情况下,这通常会发送大量无价值的数据(稍后在日志中被覆盖,除非我在发送之前在流和客户端之间进行一些压缩)但它比更优雅到目前为止的其他解决方案。
【解决方案2】:

为什么不先启动流,然后请求快照?

  1. 启动流并将所有收到的记录排队
  2. 请求快照
  3. 处理快照
  4. 处理排队的流条目(并忽略早于快照的条目)
  5. 处理流

在处理完快照之前,不要处理流中的任何内容(仅将其排队以供内部处理)。

每条记录都应该有某种标记,用于标识记录何时更改。因此,如果流包含比快照中的记录更旧的记录,只需不处理它(在同步阶段)

【讨论】:

  • 谢谢。问题是生成快照的数据库是不同的集群。这仍然需要对流服务器做出不可能的假设,即不会错过在启动流的同时提交的消息。 apache pulsar 的维护者提出的一个解决方案是,将更改通过流服务器后持久化到 db,并将 streamId 与实体一起持久化。然后,您可以使用快照获取最后一个 streamId,然后您可以使用它从指定位置启动流。将相应地更新问题
猜你喜欢
  • 2012-09-26
  • 2013-11-16
  • 1970-01-01
  • 2020-03-08
  • 2015-10-22
  • 1970-01-01
  • 2014-05-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多