事件采购模式中的聚合

问题描述 投票:1回答:1

我正在尝试采用事件采购模式并尝试理解聚合。我已经阅读了一些博客,现在我比以往任何时候都更加困惑。

从我推断的聚合应该以某种方式使用户能够在事件存储上运行不同的查询以检索不同的事件流。

使用案例:

  1. 我想在发票上重播事件,我希望看到特定员工在余额上完成的所有操作。
  2. 我想重播发票上的所有活动

我希望这些是有效的用例。

活动商店:

| event_id | invoice_id | EmployeeId | Event            | Payload |
|----------|------------|------------|------------------|---------|
| 1        | 12345      | 12345      | Invoice_InReview | JSON    |
| 2        | 12345      | 12345      | Invoice_Billed   | JSON    |
| 3        | 12345      | 45567      | Invoice_Paid     | JSON    |
| 4        | 12345      | 77341      | Invoice_Reversed | JSON    |
| 5        | 12345      | 98421      | Invoice_Paid     | JSON    |

JSON包含有关付款变更,调整和发票状态的信息状态为(审核,结算,付费)

所以根据我的理解,需要有5个组件。

  1. 事件 - 特定事件。
  2. 事件源 - 调用repo以获取相关事件的服务
  3. 事件流 - 事件列表
  4. 命令 - 发票上的请求操作
  5. Aggregate - 用于决定加载事件的输入的api

我理解其他事情如何发挥,但很难将我的头围绕在Aggregate周围。它是什么 ?

我有两个聚合课程吗?

  • AggregateEventsByInvoice
  • AggregateEventsByInvoiceEmployee

我真的很难弄清楚聚合的需要和使用。我见过的所有例子都使用了对我来说根本没有意义的UUID?任何帮助将不胜感激。

java aggregate microservices event-sourcing
1个回答
4
投票

我正在尝试采用事件采购模式并尝试理解聚合。我已经阅读了一些博客,现在我比以往任何时候都更加困惑。

那不是你的错。

聚合的概念来自Eric Evans对域建模的描述。

在典型的部署中,我们有一个充满了我们想要跟踪的事实的数据库。我们有一个模型,其中这些事实随着时间而变化。我们希望确保正确跟踪这些更改,这意味着不会引入不一致。

对此的粗略回答是我们将数据库“置于”域模型“后面”,其中包括应该如何允许数据库中的数据更改的所有规则。在Evans时代,域模型是位于应用程序层和持久层之间的层。现在,您更有可能听到“组件”或“模块”而不是层,但角色没有太大变化:保护数据库免受不正确的更改。

如果我们仔细检查域,我们通常会在模型中找到具有有趣属性的数据集群:更改集群状态的规则不依赖于集群外的任何信息。

示例:在交易应用程序中,匹配和处理某些商品的出价和报价。但是匹配一种商品(黄金)的规则完全独立于与不同商品(冷冻浓缩橙汁)相关的数据。您无需了解FCOJ中正在处理黄金交易活动的情况,反之亦然。

这些可以单独考虑的集群是聚合。

隔离的两个关键属性是

  • 聚合内部状态的更改不依赖于聚合之外的更改
  • 在聚合之外进行的更改不依赖于聚合内部所做的更改

因此,在这个例子中,我们可能有一个TradeBook“聚合”为Gold,而TradeBook“聚合”为FCOJ。要处理订单,您需要加载所需的聚合,对其应用更改并保存,而无需触及另一个。

我有两个聚合课程吗?

  • AggregateEventsByInvoice
  • AggregateEventsByInvoiceEmployee

不,您可能会根据相同的事件历史记录有两个视图或投影。

更准确地说,在Evans描述的体系结构中,会有一个“聚合根”,并且每个用例在API中都是该聚合的不同查询。

但最近,实践是认识到读取的用例不需要与写入的用例相同的约束。因此,今天您更有可能看到每个用例的视图(或投影),其中每个用例的内存表示都是根据数据存储中记录的事件构建的。

所以我理解的是聚合本质上是能够唯一识别与单个实例相关的所有事件的任何事物(在我的情况下是发票)。所以在我的情况下,invoiceId可以被视为聚合吗?

不会。在您的情况下,发票可能是汇总的。

更准确地说,您的域模型可能会协调每张发票的余额,调整,状态和付款之间的变化;这些值是我之前谈论的那种集群的一个例子。您可以更改这些值,而无需考虑调整Invoice [67890]。

所以我理解的是聚合本质上是能够唯一识别与单个实例相关的所有事件的任何事物(在我的情况下是发票)。

问题是这种理解与现有文献不一致,很可能导致沟通混乱。

在文档存储或键值存储中,聚合类似于文档,而不是用于查找文档的键。在RDBMS中,聚合将是相关实体,id将是您用于加载实体的主键。在事件存储中,流的内容描述了聚合中事件的更改,id只是用于查找正确事件的键。

事件存储是否可以使用不是聚合ID的其他列

当然 - 您可以在活动中存储您喜欢的任何元数据。创建其他列可以提高查询性能,更轻松地对数据进行分片,等等。

我们是否可以尝试从事件存储中加载查询列的事件以及聚合它? (在这种情况下,发票ID,员工ID)。

当然,您可以按照自己喜欢的方式查询事件。

什么可能不是一个好主意,试图通过重放任意一组事件来恢复域模型的当前状态。

在您的示例中,事件[1,2,3,4,5]合在一起讲述了有关发票的连贯故事。但试图从事件[4]本身了解发票可能无法让你到任何地方。

请记住,事件通常不是变更后模型状态的完整表示,而是对变更事物的描述。想想“补丁”,而不是“快照”。

© www.soinside.com 2019 - 2024. All rights reserved.