Azure functions 与事件来源和CQR的聚合

Azure functions 与事件来源和CQR的聚合,azure-functions,azure-cosmosdb,cqrs,event-sourcing,materialized-views,Azure Functions,Azure Cosmosdb,Cqrs,Event Sourcing,Materialized Views,为了处理大量遥测数据,并且仍然能够对数据执行快速查询,我采用了使用Azure函数和Azure Cosmos DB的事件源/CQRS模式 在我的体系结构中,入站遥测流存储在Cosmos DB集合中,充当事件存储 为了创建原始遥测数据的物化视图,我使用了另一个Azure函数和Cosmos DB触发器,该函数在我的事件存储中存储的所有新文档上都处于活动状态,并对这些文档执行转换 在每个文档的基础上处理一个文档是非常容易的。 棘手的是,当我需要引用其他文档来计算我的物化视图时 例如,当接收到的遥测事件包

为了处理大量遥测数据,并且仍然能够对数据执行快速查询,我采用了使用Azure函数和Azure Cosmos DB的事件源/CQRS模式

在我的体系结构中,入站遥测流存储在Cosmos DB集合中,充当事件存储

为了创建原始遥测数据的物化视图,我使用了另一个Azure函数和Cosmos DB触发器,该函数在我的事件存储中存储的所有新文档上都处于活动状态,并对这些文档执行转换

在每个文档的基础上处理一个文档是非常容易的。 棘手的是,当我需要引用其他文档来计算我的物化视图时

例如,当接收到的遥测事件包含相对计数器值时(例如,特定操作中使用的能量)。在我的物化视图中,我希望有一个包含所有能耗总和的文档

现在,一个简单的实现是在我的物化视图中查看该文档的当前状态,并通过新接收的值来增加该值

使用这种方法可能遇到的问题是,我必须重新计算物化视图,因为在未来的版本中,我需要生成一些额外的视图

对于重新计算,我只需在我的事件存储中点击我想要重新计算的所有相关文档,触发Azure函数,再次计算物化视图。这将导致进入此Azure函数的文档在之前已处理过

当重新计算发生时,如果我只是简单地增加我的总和,我的计数器将不再准确,因为已经是总和一部分的文档将再次被添加

解决这个重新计算场景(我想到)的方法是:

  • 跟踪sum中的所有源文档并忽略 已成为总和一部分的文档的事件
  • 跟踪已经是总和一部分的最新遥测事件的序列号,并在重新计算时忽略序列号低于已经是总和一部分的事件

你能给我一些关于如何正确解决这种情况的建议吗?

因此,总结一下@Mikhail和@RomanEremin的评论和我的想法,这将是处理这些情况的方法:

在重新计算视图的情况下:

  • 删除现有聚合并从头开始构建,重播 事件存储中的事件
如果事件总线交付“至少一次”(Azure函数与CosmosDb触发器的行为方式是底层ChangeFeedProcessor的结果):

  • 版本1:在聚合文档中跟踪作为聚合一部分的事件ID(文档ID),并忽略已经是聚合一部分的事件
  • 版本2:提供源事件的顺序版本(序列号),并在聚合文档中存储聚合所基于的版本。计算聚合时,请对照事件的序列号检查此序列号。如果事件的序列号低于聚合文档:忽略,否则重新计算聚合并更新聚合所基于的序列号

通常,当重新计算物化视图时,只需删除旧值,整个计算从头开始。在同一计算中多次重放同一事件对我来说不太合适。谢谢你的评论,@Mikhail!在重播场景中,您的建议将是一个很好的解决方案,但我认为当我考虑通过changefeed传递消息的“至少一次”行为时,我需要某种程度的idemopotency来计算这种物化视图。有鉴于此,在正常执行期间,消息可能会被多次传递。如果发生这种情况,我的总数将不正确。对于这些情况,您有什么建议吗?您可以存储合理数量的上次应用的事件ID,以确保没有两次应用事件。此外,如果您的写入端使用乐观锁定,您将在每个事件中使用aggregateID和序列版本。然后,您可以跟踪您的聚合在读取模型中的版本。如果您有一个事件丢失,或者发送了两次,您可以跟踪它。@MarkusS,如果您的事件总线“至少发送了一次”,则可以。但是我同意米哈伊尔的观点——如果你改变了阅读模型代码,你应该从头开始重建它。