我通读了Lagom文档,并且已经编写了一些相互交互的小型服务。但是,因为这是我第一次尝试CQRS,所以我仍然遇到一些关于持久读取方面的概念性问题,而我并不太了解。
例如,我有一个用户服务,其中包含用户列表(作为汇总)及其个人资料数据,例如电子邮件地址,名称,地址等。
我现在的问题是
如果我想在给定特定电子邮件地址的情况下检索用户个人资料,是否应在读取侧查询用户ID,然后使用该ID查询事件存储以获取个人资料数据?还是阅读方已经保留了所有配置文件信息?
如果读取端具有所有信息,那么事件存储的原因是什么?如果它确实是只写的,那不是很有用吗?
我应该设计我的系统以使我可以尽可能多地使用事件存储,还是应该对所有内容都具有读取侧?可伸缩性意味着什么?
如果用户模型发生更改(例如,配置文件现在包含配置文件的说明),并且我使用包含所有配置文件数据的读取侧,则如何更新当前在lagom中的读取侧还包含此说明吗?
接下来的问题,我应该为配置文件的不同字段保留不同的读取侧表,而不是包含整个配置文件的一个表
如果其他服务需要访问数据,它应该总是询问用户服务,还是应该根据需要保留自己的读取端?如果是后者,这是否违反CQRS原则,即拥有数据的服务应该是唯一读写数据的服务?
如您所见,整个概念还没有真正被“点击”,我很感谢答案和/或一些指导。
答案 0 :(得分:1)
如果我想在给定特定电子邮件地址的情况下检索用户个人资料,是否应在读取侧查询用户ID,然后使用该ID查询事件存储中的个人资料数据?还是阅读方已经保留了所有个人资料信息?
您应该使用专门设计的ReadModel来使用电子邮件地址搜索配置文件。您应该仅查询事件存储以重新聚合聚合,而仅重新聚合聚合以发送命令而不查询。在CQRS中,可能不会查询聚合。
如果读取端具有所有信息,那么事件存储的原因是什么?如果它确实是只写的,那不是很有用吗?
事件存储是写端的真实来源(聚合)。它用于在处理命令之前对聚合进行补水(它们根据先前发出的事件重建其内部和私有状态),并保留新事件。因此,事件存储是仅追加的,但也用于读取事件流(由Aggregate实例发出的事件)。事件存储可确保一个Aggregate实例(由类型和ID标识)一次只能处理一条命令。
如果用户模型发生更改(例如,配置文件现在包含配置文件的说明),并且我使用了包含所有配置文件数据的读取侧,则如何在lagom中更新此读取侧以现在也包含此配置文件描述?
除了我自己的框架外,我不使用任何其他框架,但是我猜您需要重写(以在事件上使用新添加的字段)并重建ReadModel。
接下来的问题是,我应该为配置文件的不同字段保留不同的读取表,而不是包含整个配置文件的一个表
对于每个用例,您应该有一个单独的ReadModel(具有自己的表)。 ReadModel应该很快,这意味着它应该尽可能的小,仅包含特定用例所需的字段。这非常重要,这是使用CQRS的主要好处之一。
如果其他服务需要访问数据,它应该总是询问用户服务,还是应该根据需要保留自己的读取端?如果是后者,这是否违反CQRS原则,即拥有数据的服务应该是唯一读写该数据的服务?
这里取决于您,建筑师。最好每个ReadModel都拥有自己的数据,也就是说,它应该订阅正确的事件,而不应该依赖于其他ReadModel。但这会导致很多代码重复。根据我的经验,我渴望拥有一些规范的ReadModel,这些ReadModels拥有一些数据,但也可以按需共享。为此,在CQRS中,还存在术语query
。就像命令和事件一样,查询可以在您的系统中传播,但只能从ReadModel到ReadModel。
在客户的请求期间不应发送查询。它们应仅作为异步同步机制在后台发送。这是影响系统弹性和响应能力的重要方面。
我还使用实时查询,当答案更改时,实时查询会实时从权威ReadModels推送到订阅的ReadModels。
如果是后者,这是否违反CQRS原则,即拥有数据的服务应该是唯一读取和写入该数据的服务?
不,不是。 CQRS并未指定R
(读取端)的更新方式,只是R
不应该处理命令并且C
不应该被查询。>