如何在事件源应用程序中管理读取请求
How to manage read requests in an event sourced application
我被要求在事件溯源方面做一些探索。我的 objective 是创建一个微小的 API 层来满足所有传统的 CRUD 操作。我现在正在使用一个名为 'sourced' 的包并尝试使用它(使用 Nodejs)。
然而,我开始意识到事件溯源在单独使用时并不是很有用。通常,它与 CQRS 结合使用。
我对CQRS的理解是,当UI向服务器发送写命令时。该应用程序对数据进行了一些验证。并将其保存在事件存储中(我正在使用 mongoDB),例如:我的事件存储应该如下所示:
{method:"createAccount",name:"user1", account:1}
{method:"deposit",name:"user1",account: 1 , amount:100}
{method:"deposit",name:"user1",account: 1 , amount:100}
{method:"deposit",name:"user1",account: 1 , amount:100}
{method:"withdraw",name:"user1",account1,amount:250}
它包含所有审计信息而不是最终状态。
但是,我很困惑如何处理读取操作。如果我想读取帐户余额怎么办。到底会发生什么?
这是我的问题:
- 如果不能直接查询event store(数据库)进行读操作,那么应该去哪里查询呢?它应该是内存中的缓存吗?
- 如果我们查询内存。是最终状态已经存在,还是我必须重播(或左折叠)操作来计算结果。例如账户1的余额为50
- 我发现一些博主谈论 'subscribe' 或 'broadcast'。它们是什么并向谁广播?
非常感谢任何建议,如果我的理解有误,请指正。
尼克问得好。您缺少的概念是 'Projections'。当一个事件持续存在时,您就可以广播该事件。您的投影代码侦听特定事件,然后执行诸如更新和创建 'read model' 之类的操作。读取模型是结束状态的一个版本(通常持久化但可以在内存中完成)。
好处是您可以针对阅读高度优化这些阅读模型。告别复杂低效的连接等
因为读取模型不是真实的来源,它是专门为读取而设计的,所以其中有数据重复是可以的。只要确保在收到适当的事件时对其进行管理即可。
有关更多信息,请查看这些文章:
- Overview of a Typical CQRS and ES Application**
- How to Build a Master Details View when using CQRS and Event Sourcing
- Handling Concurrency Conflicts in a CQRS and Event Sourced system
希望你觉得这些有用。
** 该图指的是非规范化,它应该是在谈论投影。
您可以查询事件存储。查询的实际方法特定于每个实现,但通常您可以轮询事件或订阅并在新事件持续存在时收到通知。
事件存储只是写端的持久化,保证写操作的强一致性和读操作的最终一致性。为了 "understand" 事件中的某些内容,您需要将这些事件投影到读取模型,然后查询读取模型。例如,您可以有一个读取模型,其中包含每个帐户的当前余额作为 MongoDB 集合。
我被要求在事件溯源方面做一些探索。我的 objective 是创建一个微小的 API 层来满足所有传统的 CRUD 操作。我现在正在使用一个名为 'sourced' 的包并尝试使用它(使用 Nodejs)。
然而,我开始意识到事件溯源在单独使用时并不是很有用。通常,它与 CQRS 结合使用。
我对CQRS的理解是,当UI向服务器发送写命令时。该应用程序对数据进行了一些验证。并将其保存在事件存储中(我正在使用 mongoDB),例如:我的事件存储应该如下所示:
{method:"createAccount",name:"user1", account:1}
{method:"deposit",name:"user1",account: 1 , amount:100}
{method:"deposit",name:"user1",account: 1 , amount:100}
{method:"deposit",name:"user1",account: 1 , amount:100}
{method:"withdraw",name:"user1",account1,amount:250}
它包含所有审计信息而不是最终状态。 但是,我很困惑如何处理读取操作。如果我想读取帐户余额怎么办。到底会发生什么? 这是我的问题:
- 如果不能直接查询event store(数据库)进行读操作,那么应该去哪里查询呢?它应该是内存中的缓存吗?
- 如果我们查询内存。是最终状态已经存在,还是我必须重播(或左折叠)操作来计算结果。例如账户1的余额为50
- 我发现一些博主谈论 'subscribe' 或 'broadcast'。它们是什么并向谁广播?
非常感谢任何建议,如果我的理解有误,请指正。
尼克问得好。您缺少的概念是 'Projections'。当一个事件持续存在时,您就可以广播该事件。您的投影代码侦听特定事件,然后执行诸如更新和创建 'read model' 之类的操作。读取模型是结束状态的一个版本(通常持久化但可以在内存中完成)。
好处是您可以针对阅读高度优化这些阅读模型。告别复杂低效的连接等
因为读取模型不是真实的来源,它是专门为读取而设计的,所以其中有数据重复是可以的。只要确保在收到适当的事件时对其进行管理即可。
有关更多信息,请查看这些文章:
- Overview of a Typical CQRS and ES Application**
- How to Build a Master Details View when using CQRS and Event Sourcing
- Handling Concurrency Conflicts in a CQRS and Event Sourced system
希望你觉得这些有用。
** 该图指的是非规范化,它应该是在谈论投影。
您可以查询事件存储。查询的实际方法特定于每个实现,但通常您可以轮询事件或订阅并在新事件持续存在时收到通知。
事件存储只是写端的持久化,保证写操作的强一致性和读操作的最终一致性。为了 "understand" 事件中的某些内容,您需要将这些事件投影到读取模型,然后查询读取模型。例如,您可以有一个读取模型,其中包含每个帐户的当前余额作为 MongoDB 集合。