domain-driven-design - 事件源系统中的流聚合关系

标签 domain-driven-design cqrs event-sourcing

因此,我试图弄清楚 CQRS+ES 架构的一般用例背后的结构,而我遇到的问题之一是聚合在事件存储中的表示方式。如果我们将事件分成流,流到底代表什么?在一个假设的库存管理系统的上下文中,该系统跟踪一组项目,每个项目都有一个 ID、产品代码和位置,我在可视化系统布局时遇到了麻烦。

根据我在互联网上收集到的信息,可以简洁地描述为“每个聚合一个流”。所以我会有一个 Inventory 聚合,一个带有 ItemAdded、ItemPulled、ItemRestocked 等事件的单个流,每个事件都带有包含 Item ID、数量变化、位置等的序列化数据。聚合根将包含 InventoryItem 对象的集合(每个对象都有它们各自的数量、产品代码、位置等)这似乎可以轻松执行域规则,但我认为这是一个主要缺陷;将这些事件应用于聚合根时,您必须首先重建 InventoryItem 的集合。即使使用快照,对于大量项目,这似乎也是非常低效的。

另一种方法是让每个 InventoryItem 有一个流跟踪与仅项目有关的所有事件。每个流都以该项目的 ID 命名。这似乎是更简单的路线,但现在您将如何执行域规则,例如确保产品代码是唯一的,或者您不会将多个项目放在同一个位置?看起来您现在必须引入一个 Read 模型,但将命令和查询分开不是重点吗?就是感觉不对。

所以我的问题是“哪个是正确的?”部分两者兼而有之?两者都不?像大多数事情一样,我学得越多,我学到的东西就越多,我不知道......

最佳答案

在典型的事件存储中,每个事件流都是一个独立的事务边界。每当您更改模型时,您都会锁定流、追加新事件并释放锁定。 (在使用乐观并发的设计中,边界是相同的,但“锁定”机制略有不同)。

您几乎肯定会希望确保任何聚合都包含在单个流中——在两个流之间共享一个聚合类似于在两个数据库之间共享一个聚合。

单个流可以专用于单个聚合、聚合集合,甚至整个模型。属于同一个流的聚合可以在同一个事务中更改——huzzah! -- 以从流中加载聚合时的一些争用和一些额外的工作为代价。

最常讨论的设计将每个逻辑流分配给单个聚合。

That seems like it would allow for easily enforcing domain rules, but I see one major flaw to this; when applying those events to the aggregate root, you would have to first rebuild that collection of InventoryItem. Even with snapshotting, that seems be very inefficient with a large number of items.



有几种可能性;在某些模型中,尤其是那些具有强时间分量的模型中,将某些“实体”建模为聚合的时间序列是有意义的。例如,在调度系统中,而不是 Bobs Calendar你可能有 Bobs March Calendar , Bobs April Calendar等等。将生命周期分成更小的部分可以控制事件计数。

另一种可能性是快照,它有一个额外的技巧:每个快照都用元数据进行注释,描述快照在流中的位置,您只需从该点向前读取流。

当然,这取决于支持随机访问的事件流的实现,或允许您后进先出读取的流的实现。

请记住,这两个都是真正的性能优化,first rule of optimization是……不要。

关于domain-driven-design - 事件源系统中的流聚合关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49288197/

相关文章:

php - 实体内部的 DDD 和 Doctrine 映射

c# - 领域服务的最佳设计

domain-driven-design - 我应该在没有事件存储的系统中避免聚合 (DDD) 吗?

c# - 发送命令后更新 UI

c# - 如何通过除ID以外的其他属性查询聚合根?

architecture - DDD/在图数据库中存储领域事件

domain-driven-design - 访问子类聚合成员

database - 两阶段提交会导致什么问题?

c# - MVC5 异步操作结果。那可能吗?

elasticsearch - CQRS为什么不只对读和写都进行elasticsearch?