MongoDB查找和监视。

4
我正试图实现一个通过使用查找和监视组合来保持自我更新的结构。例如,对于用户集合,我们查找所有用户并将它们存储在哈希映射表中。之后,我们打开观察流,并根据传入的事件更新我们的哈希映射表。但是有一个问题-如果在读取用户和打开流之间发生更改,我们可能会出现不同步的情况。
我的想法是使用startAtOperationTime选项,但我们无法可靠地知道所需的时间戳。此外,我不知道如何使用事务完成它。
问题是-我们如何在读取操作后精确地打开更改流而不丢失任何数据。

1
先打开更改流,然后再执行查找操作,这样行得通吗? - Joe
但是在查找完成之前可能会发生事件。我们最终会应用它两次。@Joe - user10441785
这是正确的。如果在处理查找时发生了写入操作,它可能会或可能不会包含在查找结果中,因此您仍需要进行检查。 - Joe
1个回答

3

很棒的问题。

在不知道这些增量应用于哪个初始状态的情况下,带有发出的 delta 更改的手表是相当无用的,因此当然需要进行查找。 据我所知,Mongo 没有原子的“查找和监听”命令。

即使从问题中删除增量并仅使用fullDocument=updateLookup选项,仍然存在同步问题。 考虑以下方法:

  1. collection.watch()
  2. changeStream.pause()
  3. await collection.find().toArray()
  4. changeStream.resume()

我们需要首先设置监听,以便在查找时捕获任何事件。乍一看,这看起来不错。如果在查找过程中发生了某些事情,并且在流中有一些更改事件,则恢复时会处理这些事件。由于在查找之前启动了监听,最坏的情况是更改流包含在查找之前发生的一些更改,可能会导致保存旧状态。但这通常并不重要,因为更改流还将包含最近的更新,并最终保存正确的状态。

但是,监听是否实际在查找之前在 Mongo 集群上运行?

查找查询是否甚至已经到达了正确同步的节点?

由于统一拓扑和连接池的概念,我认为我们不可能知道这些问题的答案。 我们不知道上述命令行将最终使用哪个连接。 如果 Mongo 离线,客户端将缓冲诸如 watch 和 find 的命令,然后在连接可用于连接池时释放它们。但是由于涉及多个连接(可能会在恰好的时刻抽喉),因此无法保证第 1 行中的 watch 命令会在第 3 行中的 find 命令之前到达 Mongo。 因此,我非常确定此答案在 99% 的情况下有效,但它并不是 100% 可靠。

您可以尝试通过检查resumeTokenChanged事件来确认 changeStream 是否已连接,然后进行查找,但如果您的集群出现了某些节点 oplog 同步时间较长的问题,则仍可能“查找()”旧数据并进行过晚的监听。 这意味着有未处理的更新。

更新

我认为我们所能希望的最佳解决方案是结合以上所有内容,并根据所需的群集同步优雅期间添加延迟。

  1. collection.watch():监听集合中文档的更改。
  2. 等待resumeTokenChanged事件,确保changeStream已更新到最新状态并已连接。
  3. 设置超时时间,如果一段时间内没有收到resumeTokenChanged事件,认为changeStream过期,意味着数据也可能过期。
  4. 等待集群节点同步的宽限期。
  5. changeStream.pause():暂停从changeStream中接收更改事件。
  6. 如果仍未从changeStream接收到任何change事件,则执行await collection.find().toArray()操作。
  7. changeStream.resume():恢复从changeStream中接收更改事件。
  8. 如果changeStream发出error事件,则重新开始整个过程。

非常有见地!您的解决方案中,您认为对于查找操作使用“primary”读取优先级(如果您想要防止回滚场景,则使用“majority”读取关注)是否可以消除错过更新的机会,并使得简化流程成为可能,即1)观察,2)等待事件,3)查找? - tgnottingham

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接