3

描述

我正在开发一个 ASP.NET Core 3.1 Web 应用程序,该应用程序需要跟踪/响应对 Azure Cosmos DB(版本 3.6)托管的 MongoDB 数据库所做的更改。为此,我使用了Change feed support

更改非常频繁:集合中的单个条目每秒更新约 10 次。

为了追踪对集合所做的更改,我使用以下代码将受影响的条目转储到文件中(这仅用于测试目的)。

private async Task HandleChangeStreamAsync<T>(IMongoCollection<T> coll, StreamWriter file, CancellationToken cancellationToken = default)
{
    var pipeline = new EmptyPipelineDefinition<ChangeStreamDocument<T>>()
            .Match(change => change.OperationType == ChangeStreamOperationType.Insert || 
                             change.OperationType == ChangeStreamOperationType.Update || 
                             change.OperationType == ChangeStreamOperationType.Replace)
            .AppendStage<ChangeStreamDocument<T>, ChangeStreamDocument<T>, ChangeStreamOutputWrapper<T>>(
                  "{ $project: { '_id': 1, 'fullDocument': 1, 'ns': 1, 'documentKey': 1 }}");

    var options = new ChangeStreamOptions
    {
        FullDocument = ChangeStreamFullDocumentOption.UpdateLookup
    };

    using (var cursor = await coll.WatchAsync(pipeline, options, cancellationToken))
    {
        await cursor.ForEachAsync(async change =>
        {
            var json = change.fullDocument.ToJson(new JsonWriterSettings { Indent = true });
            await file.WriteLineAsync(json);
        }, cancellationToken);
    }
}

问题

在观察输出时,我注意到对集合进行的每次更新都没有触发更改提要。我可以通过将生成的输出与 MongoDB Cloud 托管的数据库进行比较来确认这一点。

问题

  1. Azure Cosmos DB 的 MongoDB API 中的更改流支持有多可靠?

  2. API 能否保证最新的更新始终可用?

  3. 我无法自己处理“本地”数据库的“oplog.rs”集合,API 是否以任何方式支持这一点?这甚至受到鼓励吗?

  4. 收集吞吐量 (RU/s) 是否以某种方式与更改事件频率相关?

最后的想法

我的理解是频繁的更新会限制系统,并且更改源根本无法处理日志中的所有事件(而是定期扫描它)。但是,我想知道依靠这种机制有多安全,并确保不会错过对数据库进行的任何关键更新。

如果更改提要支持无法对事件处理频率做出任何保证并且无法处理“oplog.rs”,则唯一的选择似乎是定期轮询数据库。

如果我错了,请纠正我,但切换到轮询会极大地影响性能,并会导致解决方案不可扩展。

4

1 回答 1

6

我怀疑 MongoDB 更改流是基于 Cosmos DB 更改源构建的。我的经验完全来自 Cosmos DB 更改提要;我根本没有使用过 MongoDB API。所以这个答案都是假设 MongoDB 更改流在内部使用 Cosmos DB 更改源,这是有道理的,但我可能是错的。

Azure Cosmos DB 的 MongoDB API 中的更改流支持有多可靠?

它是完全可靠的,但有一些限制。

更改提要的限制之一是它可以“批量”更新。在内部,更改提要处理器轮询更改提要,它将获取所有已更改的项目。但是,如果一个项目在轮询之间多次更改,它只会在更改提要中显示一次。这是 Cosmos DB SQL API 更改源的行为,我希望 MongoDB 更改流也有同样的限制,尽管我没有看到它实际上记录在 MongoDB 文档的任何地方。

另一个限制是没有观察到删除。

由于这些限制,变更馈送/变更流不是事件溯源解决方案。如果您想要事件溯源,那么您需要自己将数据建模为事件;没有任何内置功能可以为您做到这一点。

也就是说,在这些限制范围内,它是完全可靠的,因为您的代码将接收更改提要中的每个更改文档。这些限制只是意味着多个更新可能会作为一个更改的文档出现,而删除的文档根本不会出现。

API 能否保证最新的更新始终可用?

在您的代码从更改提要中检索文档后,文档总是有可能发生更改,在这种情况下,更新后的文档将重新发布到更改提要,您的代码稍后会再次看到它。(当然)不能保证您的代码刚刚从更改提要中获得的文档与数据库中的文档相同,但最终会保持一致。

我无法自己处理“本地”数据库的“oplog.rs”集合,API 是否以任何方式支持这一点?这甚至受到鼓励吗?

¯\ (ツ)

收集吞吐量 (RU/s) 是否以某种方式与更改事件频率相关?

是的。更改提要本身内置于 Cosmos DB,但更改提要处理具有 RU 成本。变更提要处理器使用 RU 来轮询变更提要,从变更提要中读取文档,并更新其“书签”以跟踪它在变更提要中的位置。

我的理解是频繁的更新会限制系统,并且更改源根本无法处理日志中的所有事件(而是定期扫描它)。

那是对的。

但是,我想知道依靠这种机制有多安全,并确保不会错过对数据库进行的任何关键更新。

代码将始终(最终)接收更新的文档。但是,如果您需要单独查看每个更改,那么您将需要使用事件溯源之类的东西来构建数据。如果您的应用只关心文档的最终状态,那么更改提要就可以了。但是,例如,如果您需要知道是否someCriticalProperty设置为true然后返回到false,那么您将需要事件溯源。

切换到轮询会极大地影响性能,并导致解决方案不可扩展。

投票不一定是坏事。如上所述,更改馈送处理器使用轮询。它还有一个允许横向扩展的简洁机制,其中不同的处理器观察同一个集合可以拆分它们之间的文档(通过分区键);我不确定这是否/如何转化为 MongoDB 世界,但它是一个非常优雅的解决方案,用于扩展 SQL API 更改提要处理器,并且与 Azure Functions 配合得非常好(不幸的是,Azure Functions 没有 MongoDB 更改流触发器)。

于 2021-03-26T12:53:06.610 回答