我将为您提供一些我使用过/见过使用过的基本事件溯源术语。另外,我将在 CQRS 的上下文中使用事件溯源,尽管它可以单独使用(我直到现在才这样做)。
事件存储是事件的持久性(数据库)。应用程序的写/命令和读/查询端对事件存储有不同的要求。
写入端需要聚合发出的事件必须按顺序并防止并发插入。人们将此称为 事件流 = 聚合实例(即 Product#1234)发出的所有事件。 Event 流在读取的时候也应该很快,也就是说,从 Event 流中按照发出的顺序读取所有的事件,最早的在前,应该很快;这是在执行每个命令之前进行聚合补水所必需的。
读取方希望所有事件按总顺序排列,跨越所有聚合。如果您负担得起这个要求,那么 Readmodel 的构建会更简单。但是,通过更大的开发和设计工作,可以创建不需要全序的读取模型。
大型系统的问题在于,一般来说,Readmodels 需要来自多个事件存储的事件
事件源是事件流的集合吗?
如果“事件源”是指“事件存储”,那么是。
每个有界上下文都有一个事件源吗?或者可能是每个 DDD 聚合(例如汽车及其更改)?
最简单的系统是具有单个事件存储实例的系统。这是因为 Readmodels 只需要连接到一个实例,并且您可以拥有事件的总顺序。
如果系统太大,则不可能拥有单个事件存储。这意味着您不能拥有事件的总顺序,这意味着读取模型更难构建(并非不可能)并且运营成本会增加。
因此,您必须做出权衡。一个不错的权衡是每个有界上下文都有一个事件存储。
每个事件源都有自己的数据存储吗?
这个问题在这个答案的上下文中没有意义。一个事件存储 = 一个数据存储。
以汽车的事件源为例,其中每个事件流都基于唯一的 carId?
是的,每个汽车实例(具有唯一 ID)都有一个事件流。
客户端 --> eventStore API --> 存储事件 --> 可能将消息发布到队列 --> 向客户表示赞许 --> 去构建您的读取模型/索引? --> 客户端公开发布事件 --> 同一事件的其他消费者现在可以根据该事件采取行动。
这取决于您的架构/风格/Readmodels 如何接收事件。
您可能有一个简单的同步系统,当在同一个进程/线程中处理命令,发出事件时,它们会立即持久化到事件存储中,然后所有的 Readmodel 和 Sagas 都会收到这些新事件,全部同步完成,一个接一个。
一个更复杂的系统执行命令,将事件持久化到事件存储,然后将响应返回给客户端。在一个单独的过程中,Readmodels 和 Sagas 轮询来自 Event store(提供此类 API)的新事件并在后台处理它们。
其他解决方案使用消息队列;这有点难以做到,因为不能以一种安全且可扩展的方式将事件持久保存到事件存储,并以原子方式将它们发布到消息队列(无论是成功还是无)。