事件存储:您是否需要事件存储的查询功能来创建新的预测?

Event stores: Would you need query capabilities for an event store to create new projections?

我是事件溯源的新手。据我所读和所见,事件存储被描述为具有非常基本的功能/有限的界面,这些行

getStreamForId: (streamId: ID) => Events[];
appendToStream: (streamId: ID; expectedVersion: number) => void;

虽然这工作正常并且大多数数据库架构都足够了,但重播事件以创建新投影怎么样?您不需要选择一个允许更复杂查询的数据库架构,以便您可以基于特定事件类型构建预测吗?

示例: 假设我有三个聚合订单、客户、发票。为简单起见,总共存在 12 种类型的 if 事件。

现在,几个月后出现了新的业务需求,可以通过预测每个客户的总订单量的新报告来满足该需求。为了创建此投影,我需要事件类型 2、5 和 12。

如果事件存储的查询能力有限,您将如何重播这些事件?

我的具体案例: 我必须决定项目的数据库基础设施。我在考虑 DynamoDB,它适用于上面给出的有限接口,但查询功能非常有限。由于新的 projections/report 需求可能会出现,我想知道我是否遗漏了一些关于事件溯源的基本知识,或者对事件存储的重播查询需求是事件溯源中遗漏的细节 material 我读了。

使用不同的数据库(例如 Mongo)可以很容易地仅查询类型 2、5 和 12 的事件,并且 运行 通过投影仪查询它们。

该接口是 event-sourced 聚合的最小接口(有些事件存储实现不需要公开预期版本,因为某些其他组件(例如在 Akka 中,通常是 Cluster Sharding)正在阻止(或至少使足够少的)并发更新)。

事件存储(或与事件存储交互的应用程序代码)在附加到流时可以自由地将事件(可能带有一些元数据)附加到对应于该类型(或通常是一个标签,这样相关的事件就可以一起持久化,而不必重建它们的顺序。

这基本上就是 Akka Persistence 的 Cassandra 插件(与 DynamoDB 一样,也是一个 Dynamo-inspired 存储)提供 eventsByTag 查询的方式。请注意,要保证每个具有给定标签的事件最终都会进入适当的流,这涉及很多微妙之处。

如前所述,如果您直接处理流,则可以在应用程序中完成此操作。在极限情况下,基于此 API,一个即将持久化事件的聚合可以通知进程它将持续存在,但是来自当前 version/offset 的许多事件,并在该进程确认后持久化事件.该进程本身就是 event-sourced:它的状态基本上是一组流 ID 和 version/expected 事件计数。它订阅流 ID 并将事件路由到适当的标记流。

显然,提前确定可能感兴趣的事件组合并将这些事件提供给 tagged/typed 流并不费力。感兴趣的事件可能是领域事件(如果你只是在做一个 event-driven 架构与事件源相比,你会发出的事件),而其他事件更多是聚合是 event-sourced 并且不太可能需要,因此拥有每个领域事件的流水线通常很有用:以后的混音可以订阅流水线。如果您后来发现一个消费者想要您不希望对其感兴趣的事件类型,那就需要多做一些工作,但是假设您知道哪些流来自您的聚合,您可以扫描它们并填充它新流;这是最后的手段,但它是可能的(相比之下,破坏性更新样式持久化,你不能一般地回答“此时状态是什么”的问题)。