14

我正在考虑实现一个 MongoDB 更改流阅读器,并且我想确保我做得正确。有很多关于如何实现实际阅读器代码的简单示例,包括官方文档,我不太担心它的这方面。

然而,我有点担心读者落后于变更流并且无法赶上,我想确保读者能够处理流程。

mongo 服务器是一个集群,为了争论,我们假设它在一天中的任何时候都很忙。考虑到它必须迭代流结果而不是像队列一样对其进行操作,更改流 API 似乎只与执行工作的单个实例兼容。因此,我担心迭代结果的单个实例可能需要更长的时间来完成其工作,而不是新项目被推入流中。

我的直觉是实际上让读者简单地阅读流,批量更改,然后将其推入队列,然后其他工作人员可以水平扩展以完成工作。但是,我仍然有一个实例作为读取器,并且理论上它仍然有可能落后于流,即使只做将更改推送到队列中的最低限度的工作。

所以我的问题是,这种担心有多现实?有没有办法以这样的方式创建阅读器,即使它只是将更改流式传输到工作队列中,它也可以水平扩展?我还应该考虑哪些其他因素?

4

1 回答 1

9

最有可能的是,只需将所有工作委托给一个水平缩放的队列,单个读者就足够了。

如果事实证明这还不够,并且您的阅读器仍然需要水平扩展,那么您可以通过使用匹配过滤器来实现这一点,它允许多个阅读器划分工作。

例如,如果您有一个带有十六进制字符的 id,您可以通过在每个服务器上使用匹配运算符将工作拆分到两个服务器上,其中每个服务器匹配全范围内的一半字符:

// Change Stream Reader 1
const params = [
  { $match: { _id: /^[0-7]/ } }
];
const collection = db.collection('inventory');
const changeStream = collection.watch(params);

在第二台机器上:

// Change Stream Reader 2
const params = [
  { $match: { _id: /^[8-9a-f]/ } }
];
const collection = db.collection('inventory');
const changeStream = collection.watch(params);

如果您需要超过 16 台服务器,则可以使范围更加具体:

// Server 0  matches on /^0[0-7]/
// Server 1  matches on /^1/
// ...
// Server 15 matches on /^f/
// Server 16 matches on /^0[8-9a-f]/

这将允许每台机器观看消息子集并处理它们,而其他机器正在处理其他消息而不会重复。

协调哪个服务器以稳健的方式监视哪个范围变得有些复杂,因为您需要确保崩溃或挂起的机器恢复,如果您需要动态水平扩展,那么您需要能够向服务器提供新范围并调整大小. 此解决方案还会导致消息被乱序处理,因此如果顺序很重要,那么您需要想出一个解决方案来重新排序消息或处理乱序问题。

但这些都是与这个问题不同的主题,所以我现在将省略细节。

于 2019-01-23T18:10:50.980 回答