iva*_*zan 3 azure mongodb azure-cosmosdb azure-cosmosdb-mongoapi azure-cosmosdb-changefeed
我正在开发一个 ASP.NET Core 3.1 Web 应用程序,该应用程序需要跟踪/响应对 Azure Cosmos DB(版本 3.6)托管的 MongoDB 数据库所做的更改。\n为此,我使用更改源支持。
\n更改非常频繁:集合中的单个条目每秒约更新 10 次。
\n为了跟踪对集合所做的更改,我将受影响的条目转储到文件中(这仅用于测试目的使用以下代码
\nprivate async Task HandleChangeStreamAsync<T>(IMongoCollection<T> coll, StreamWriter file, CancellationToken cancellationToken = default)\n{\n var pipeline = new EmptyPipelineDefinition<ChangeStreamDocument<T>>()\n .Match(change => change.OperationType == ChangeStreamOperationType.Insert || \n change.OperationType == ChangeStreamOperationType.Update || \n change.OperationType == ChangeStreamOperationType.Replace)\n .AppendStage<ChangeStreamDocument<T>, ChangeStreamDocument<T>, ChangeStreamOutputWrapper<T>>(\n "{ $project: { \'_id\': 1, \'fullDocument\': 1, \'ns\': 1, \'documentKey\': 1 }}");\n\n var options = new ChangeStreamOptions\n {\n FullDocument = ChangeStreamFullDocumentOption.UpdateLookup\n };\n\n using (var cursor = await coll.WatchAsync(pipeline, options, cancellationToken))\n {\n await cursor.ForEachAsync(async change =>\n {\n var json = change.fullDocument.ToJson(new JsonWriterSettings { Indent = true });\n await file.WriteLineAsync(json);\n }, cancellationToken);\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n在观察输出时,我注意到对集合进行的每次更新都不会触发更改源。我可以通过将生成的输出与 MongoDB Cloud 托管的数据库进行比较来确认这一点。
\n适用于 MongoDB 的 Azure Cosmos DB\xe2\x80\x99s API 中的更改流支持有多可靠?
\nAPI能否保证最新的更新始终可用?
\n我无法自行处理“本地”数据库的“oplog.rs”集合,API 是否以任何方式支持此操作?这还被鼓励吗?
\n收集吞吐量 (RU/s) 是否在某种程度上与更改事件频率相关?
\n如果更改源支持无法对事件处理频率做出任何保证,并且无法处理“oplog.rs”,则唯一的选择似乎是定期轮询数据库。
\n如果我错了,请纠正我,但切换到轮询会极大地影响性能,并会导致解决方案不可扩展。
\n我怀疑 MongoDB 更改流是基于 Cosmos DB 更改源构建的。我的经验完全来自于 Cosmos DB 更改源;我根本没有使用过 MongoDB API。所以这个答案都是假设 MongoDB 更改流内部使用 Cosmos DB 更改源,这是有道理的,但我可能是错的。
\n\n\n适用于 MongoDB 的 Azure Cosmos DB\xe2\x80\x99s API 中的更改流支持有多可靠?
\n
它完全可靠,但有一些局限性。
\n更改源的限制之一是它可以“批量”更新。在内部,更改源处理器轮询更改源,它将获取所有已更改的项目。但是,如果某个项目在轮询之间多次更改,则它只会在更改源中显示一次。这是 Cosmos DB SQL API 更改源的行为,我预计同样的限制也适用于 MongoDB 更改流,尽管我没有看到它在 MongoDB 文档中的任何地方实际记录。
\n另一个限制是无法观察到删除。
\n由于这些限制,变更源/变更流不是事件溯源解决方案。如果您想要事件溯源,那么您需要自己将数据建模为事件;没有任何内置功能可以为您做到这一点。
\n也就是说,在这些限制内,它是完全可靠的,因为您的代码将接收更改源中的每个更改的文档。这些限制仅意味着多个更新可能会作为单个更改的文档出现,而删除的文档根本不会出现。
\n\n\nAPI能否保证最新的更新始终可用?
\n
在您的代码从更改源检索文档后,文档总是有可能发生更改,在这种情况下,更新的文档将重新发布到更改源,并且您的代码稍后会再次看到它。(当然)不能保证您的代码刚刚从更改源获取的文档与数据库中的文档相同,但它最终会保持一致。
\n\n\n我无法自行处理“本地”数据库的“oplog.rs”集合,API 是否以任何方式支持此操作?这还被鼓励吗?
\n
\xc2\xaf\\ (\xe3\x83\x84) /\xc2\xaf
\n\n\n收集吞吐量 (RU/s) 是否在某种程度上与更改事件频率相关?
\n
是的。更改源本身内置于 Cosmos DB 中,但更改源处理会产生 RU 成本。更改源处理器使用 RU 来轮询更改源、从更改源读取文档以及更新其“书签”以跟踪它在更改源中的位置。
\n\n\n我的理解是,频繁的更新会限制系统,并且更改源根本不处理日志中的所有事件(而是定期扫描日志)。
\n
那是对的。
\n\n\n但是,我想知道依赖这种机制有多安全,并确保不要错过对数据库所做的任何关键更新。
\n
代码将始终(最终)收到更新的文档。但是,如果您需要单独查看每个更改,那么您将需要使用事件源之类的方法来构建数据。如果您的应用程序只关心文档的最终状态,那么更改源就可以了。但是,例如,如果您需要知道是否someCriticalProperty设置true为然后返回到false,那么您将需要事件溯源。
\n\n切换到轮询会极大地影响性能,并且会导致解决方案不可扩展。
\n
民意调查不一定是坏事。如上所述,变更馈送处理器使用轮询。它还具有允许横向扩展的巧妙机制,其中观察同一集合的不同处理器可以在它们之间分割文档(通过分区键);我不确定这是否/如何转化为 MongoDB 世界,但它是一个非常优雅的解决方案,用于扩展 SQL API 更改源处理器,并且与 Azure Functions 配合得很好(不幸的是,Azure Functions 没有 MongoDB 更改流触发器)。
\n