CQRS事件来源和每个微服务拥有自己的数据库

时间:2019-01-10 09:31:20

标签: events microservices cqrs event-sourcing

我在微服务架构中的事件源和客户满意度上面有一些疑问。 我知道在发送命令后,一些微服务会执行它并发出事件。事件存储在其上订阅并保存在他的数据库中。此外,一些基于此事件的ReadModel会在读取数据库中生成并保存优化的数据。

  

我的第一个问题是-微服务能否拥有自己的数据库和存储   里面的数据呢?或者也许采用事件外包方法的微服务   没有自己的数据库,所有内容都只存储在内部   活动商店?

     

我的第二个问题是-当我在微服务中执行命令时   需要一些数据进行验证,是否需要调用ReadModel或   什么?假设微服务没有自己的数据库,我没有   选择吗?

1 个答案:

答案 0 :(得分:0)

  

微服务能否拥有自己的数据库并在其中存储数据?

当然,微服务可以拥有自己的数据库。但是,让我们使用ES / CQRS中的术语。数据库可以表示事件存储(不可变事件的仅附加日志)和读取模型-某些数据库,用于回答由起诉事件填充的查询。

因此,微服务可以具有自己的读取模型,该模型由其他微服务的事件填充。

或者微服务可以处理命令并将事件保存到共享的事件存储中。

或者微服务可以处理命令并将事件保存到其自己的事件存储中。

选择是您的选择,它取决于您希望在微服务之间实现的分离程度。

我会将通常消耗的所有事件放到同一事件存储中。这意味着我应该能够查询这些事件,并因此得到一个有序的流。

  

当我在微服务中执行命令并需要一些数据进行验证时,我需要调用ReadModel还是什么?

命令由具有自己状态的Aggregate执行。通过处理此聚合的所有事件来建立此状态,并且该状态应用于验证命令。

cannot/should not talk to Read Models in the command handler,主要是因为这些读取的模型与聚合状态不一致。聚合状态是一致的。

您可以在发送命令之前查询读取模型(以确保可以发送)。但是在命令处理程序中,您只需要依赖聚合状态即可。

在著名的情况下,注册用户需要唯一的名称。作为主要验证,您可以在UI代码中查询读取模型并告诉用户输入的名称已被使用。如果未使用名称,则UI允许用户发出命令。我假设您的聚合根是用户。

但是在处理此命令({id:123, type:CREATE_USER, name:somename})时,您无法检查是否采用了“ somename”,因为用户123的聚合状态不包含采用名称的列表。您可能会查询一些AllUsernames读取模型,但是它可能是毫秒级的,并且其他一些用户可能已经使用了这个“ somename”。因此,在这种情况下,您将在添加名称以读取模型的过程中发现重复项。然后,您可以采取一些补偿措施-通常发出命令来暂停名称重复的用户,并要求他重新注册或以某种方式更改其名称。

这似乎很奇怪,但是如果您有一个真正的分布式系统,并且具有多个用户列表副本,那么您将遇到相同的问题,那么为什么不仅仅接受数据始终不完全一致这一事实,而只是处理一下呢?它吗?