CQRS事件存储的结构

13

我目前正在尝试理解如何构建事件存储的内部结构。以下是我目前得到的信息:

  • 事件存储有两个表(集合),一个用于聚合,另一个用于事件。
  • 聚合表包含以下数据:aggregateId(可能是GUID)和 aggregateVersion(它是一个整数,仅表示影响此聚合的最后一个事件的编号)。
  • 事件表包含以下数据:eventId(同样是GUID)、aggregateId(事件所属的聚合)、payloadversion(它只是描述事件顺序的整数)。

到目前为止,以上翻译是否正确? 事件应该使用整数进行排序还是应该基于时间戳进行排序?每种方法的优点是什么?缺点是什么?


我还在考虑整数(由数据库自动递增)与时间戳的问题。自动递增的数据库ID显然保证是绝对唯一的,但它可能会使从某些故障转移场景中恢复变得不可能或者最好也很困难。 - Kimble
4个回答

10

我建议您参考Jonathan Oliver的EventStore (https://github.com/joliver/EventStore)。

在SQL持久化版本中,只有一个表格。您可以轻松地不使用聚合表并将aggregateId存储在事件表中。可以通过使用max()查询来检索最新版本。

除此之外,我认为您应该在事件表中添加标题,因为总会有一些有趣的元数据不想存储在事件本身中。

此外,我认为您应该在事件表中添加日期列。

最后,您可能需要某种标志,以指示事件是否已向下游分发。这个添加使您能够在一个线程或进程中编写并在另一个线程或进程中分派。

好了,以上大致介绍了Jonathan的EventStore结构。


布尔值和索引不是朋友。 - Yves Reynhout
Yves,你是在指dispatched标志吗?我认为无论如何它都需要存在。幸运的是,我不是SQL索引方面的专家,但是“datetime null”在索引方面会有什么影响呢? - Mikael Östberg
如果您的索引涉及到集合的99%或索引中每个值都指向唯一行,那么索引的价值是多少(它可能无法很好地服务于查询,或者成为插入/更新的噩梦,找到平衡点很困难)?我会选择提前编写一个单独的表。 - Yves Reynhout
对我来说,底线是总线关注点不应该出现在事件存储中(尽管 - 像任何事情一样 - 这并不是我信仰的东西)。 - Yves Reynhout
2
放弃派遣标志。投影/视图可以负责跟踪它们的进度。这也将允许您写入仅追加存储,同时简化备份和复制。 - Kimble


4

2

这与Mark Nijhof(和据推测,Greg Young)所说的相反(根据http://cre8ivethought.com/blog/2010/02/05/cqrs-event-sourcing):“您基本上需要有一个集合,描述事件存储已持久化的所有不同对象,包括Id和Version。然后,另一个集合将包含每个不同对象的所有序列化事件,并且它们应该可以通过对象Id按其版本进行检索。因此,为了简化此过程,在关系数据库管理系统中,这意味着总共有2个表。” - Golo Roden
无论如何,如果不进行快照,则不需要两个集合。请查看 https://github.com/joliver/EventStore 以获取另一种实现。 - jamuhl
1
为什么需要构建自己的事件存储?在Node.js中已经有两个事件存储实现:https://github.com/jamuhl/nodeEventStore 或 https://github.com/brighthas/cqrsnode.store,为什么不为它们做出贡献呢? - jamuhl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接