MongoDB 变更流 reader 的水平扩展策略是什么?

What is a good horizontal scaling strategy for a MongoDB change stream reader?

我正在考虑实施 MongoDB 变更流 reader 并且我想确保我做的是正确的。有很多关于如何实现实际 reader 代码的简单示例,包括 official documentation,我不太担心这方面的问题。

不过,我有点担心 reader 落后于 变化流,无法跟上,我想确保 reader 可以处理流量。

mongo 服务器是一个集群,为了便于论证,我们假设它在一天中的所有时间都非常繁忙。更改流 API 似乎只与执行工作的单个实例兼容,因为它必须如何迭代流结果而不是像队列一样对其进行操作。因此,我担心迭代结果的单个实例可能比将新项目推送到流中花费更长的时间来完成它的工作。

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

所以我的问题是,这种担心有多现实,有没有什么方法可以创建 reader,即使它只是将更改流式传输到工作人员中,它也可以水平扩展队列?我还应该考虑哪些其他注意事项?

很可能单个 reader 只需将所有工作委派给水平缩放的队列就足够了。

如果事实证明这还不够,并且您的 reader 仍然需要水平缩放,那么您可以通过使用匹配过滤器来实现这一点,从而允许多个 reader分工。

例如,如果您有一个包含十六进制字符的 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]/

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

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

但是这些都是与这个问题不同的主题,所以我暂时不说细节。