gpt4 book ai didi

domain-driven-design - 领域事件与事件溯源和 CQRS 的因果关系

转载 作者:行者123 更新时间:2023-12-04 08:23:22 26 4
gpt4 key购买 nike

假设我们有一个生成两个事件的写入模型(域):

  • CarrierAdded(...)
  • BusConnectionCreated(运营商,...)

Carrier 和 BusConnection 类是(的一部分)独立的聚合。 BusConnection 被分配给 Carrier 并包含其 CarrierId(单独的聚合仅由 id 引用)。

在命令和事件的正常流程中,写模型和读模型都很好,但是当我们想从头开始重建/添加新的读模型时,问题就出现了。

许多人建议(例如 akka-persistence 库)事件存储在事件存储中的每个聚合中。当非规范化程序要求回复事件时,他从每个聚合中获得两个独立的事件流。问题是来自不同聚合的某些事件(如上例)需要按照它们添加到事件存储中的相同顺序进行回复。这意味着我们需要某种因果依赖性/部分排序。

最后是我的问题:

  • 我应该重新考虑我的域设计(糟糕的聚合边界?)还是
  • 我是否只需要执行部分排序?

如果是后者,最有效的方法是什么?

  • 全局柜台?似乎没有可扩展性。
  • 某种矢量时钟?
  • 在反规范器中出现此类问题时检测它们?例如。我们得到了 CarrierId,我们还没有这个 ID 的 CarrierAdded 事件,所以我们隐藏事件并先等待预期的事件
  • 在重播模式下处理事件时引入一些顺序?例如。所有与 Carriers 相关的事件都在第一位,然后是 BusConnection 相关事件?

最佳答案

不,IMO,你的设计非常好而且很常见。您必须以某种方式强制执行部分排序。

我不熟悉 akka-persistence,但一些事件存储通过记录事件的时间戳并按时间戳的顺序重放事件来实现部分排序。一些事件存储确实使用全局计数器,例如当底层数据库是关系数据库并且系统不需要扩展时——数据库提供的序列号在这里工作正常。

时间戳当然只能保证排序达到给定的粒度,通常是 1 毫秒。在某些情况下,这已经足够了,例如,如果您可以确保 CarrierAdded 从不发生在与 BusCarrierAdded 相同的毫秒内。

至于可扩展性,请确保横向扩展确实是您的问题,公共(public)汽车运输系统似乎并不“庞大”……如果您可以使用单个主数据库服务器,事件的序列号在事件流中是实现所需部分排序的直接且可靠的方法。 “交织”/并行提交的序列号可能会失败,因此您需要确保 CarrierAdded 事件始终在 BusCarrierAdded 之前添加到事件存储/数据库中,但这在您的场景中似乎很可能。

如果您确实需要横向扩展并且两个事件可能出现在同一毫秒内,您确实必须检测处理程序中的问题并使用反规范化。这听起来比实际更难,因为它可以使用非常简单的状态机轻松实现。乔纳森奥利弗有 blogged about state matchines here在 sagas 的上下文中,但原则也适用于此。

关于domain-driven-design - 领域事件与事件溯源和 CQRS 的因果关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23749156/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com