【问题标题】:How to ensure external projections are in sync when using CQRS and EventSourcing?使用 CQRS 和 EventSourcing 时如何确保外部投影同步?
【发布时间】:2015-08-13 01:55:35
【问题描述】:

我正在启动一个新应用程序,我想使用 cqrs 和事件源。我想到了重播事件以重新创建聚合和快照以在需要时加速,在内存模型、缓存等中使用。

我的问题是关于我不想保留在内存中的大型读取模型。假设我有一个销售产品的应用程序,我想监听诸如“ProductRegistered”“ProductSold”之类的事件流,并在关系数据库中构建一个表,用于报告或与另一个系统集成。假设有很多记录,并且此表可能需要几秒钟到几分钟的时间来截断/重建,并且应用程序会出于多种目的导出数十个这样的预测。

在这种情况下如何处理预测的一致性?

使用内存中的数据,回放事件非常简单和快速。但我觉得保存在磁盘中的外部预测重建速度会慢得多。

  1. 我是否应该始终使用 TRUNCATE TABLE + 重建每个外部投影来启动我的应用程序?随着时间的推移,这对我来说似乎不切实际,但我可能会担心我还没有遇到的问题。

  2. 由于表本身就像一个快照,我可以保留一个“控制表”来判断哪个事件是我为该投影处理的最后一个事件,因此我可以只重播需要的内容。但是如果应用程序或数据库崩溃,我担心会出现不一致。看来检查表的一致性和重建会是一样的,这又指向了解决方案1。

您将如何以可随时间推移进行维护的方式来处理它?有没有更好的解决方案?

非常感谢。

【问题讨论】:

  • 读取模型应该(在大多数情况下)存储在数据库中,而不是留在内存中。如果您担心由于应用程序崩溃而无法同步,那么您应该考虑使用 MSMQ 来实现事件总线。
  • 这并不能真正解决任何问题,即使使用消息队列,也存在投影可能不同步的情况。问题不在于交通。
  • 好的,如果读取模型不同步,我会将所有事件重播到读取模型。这将需要时间,具体取决于硬件、数据库等。您可以使用 事务性 MQ 最小化这种“不同步”,因为这只会在事件存储完成后崩溃发生时发生在事件发送到 MQ 之前写入。而这只是一个很小的时间间隔。
  • 如您所见,这是关于如何管理从事件存储到投影的事件传输;o)
  • 好的,我现在明白你在说什么了。如果队列是事务性的,我只会在写入投影表后确认消息接收。这解决了交付保证,您不必在应用重新启动时截断表以确保一致性。对于任何其他问题,你会重建而不关心它需要多少时间,因为它偶尔会发生。是这样吗?您可能应该写一些东西作为答案而不是评论。

标签: cqrs event-sourcing


【解决方案1】:

处理此问题的一种方法是检查点的概念。本质上,您的事件流或整个系统都有一个版本号(检查点),随着每个事件的增加而增加。

对于每个投影,您存储应用的最后提交的检查点。在启动时,您提取大于应用于投影的最后一个检查点编号的事件,并从那里继续构建您的投影。如果您需要重建投影,请删除数据和检查点并重新运行整个流(或流集)。

注意:最后应用的检查点和投影的读取模型需要保存在单个事务中,以确保它们不会不同步。

【讨论】:

  • 谢谢!这类似于我从查看 NEventStore 源中得到的结果。这似乎足以保证在单个服务器中对投影进行排序。我想知道如何在多服务器设置中做到这一点,但也许主 + 备用对于事件存储来说绰绰有余。
  • 假设我们有一个按事件流的增量版本,如果我们的投影监听来自多个流的事件怎么办?我们应该为我们收听的每个事件流保留当前版本吗?如果是这样,如果我们的投影没有监听这些流的每个事件,那么我们无法正确跟踪版本怎么办?
  • @MaximeGélinas 拥有一个全局检查点而不是(或除了)每个流版本将解决这些问题。其他可能的解决方案对于评论来说太多了。
  • @PhilSandler 我在这里提出了一个新问题:stackoverflow.com/q/56150852/5960632。如能回答将不胜感激!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多