本文是将介绍如何在微服务中实施CQRS模式,并深入探讨为什么无服务器和这种类型的系统无比契合。在最后,将介绍一个使用Spring Cloud Stream实施CQRS的参考应用。
什么是事件驱动型架构?
事件驱动型架构会优先处理领域事件,但这种架构已经逐渐被淘汰。
我们日常使用的一个示例是前端应用。在如今使用的Web浏览器中,事件的处理方法是捕获用户表单的输入数据,而连接到页面元素的事件将由一个显式映射函数来处理,在触发时在用户界面应用对状态的更改。
最近,随着微服务的广泛普及,人们对如何在分布式后端系统中利用事件驱动技术重新产生了兴趣。
CQRS
如今,事件驱动型架构中最热门的实践之一叫做CQRS,全称是命令查询责任分离。CQRS是一种架构风格,能让您使用不同模型来更新和读取领域数据。
CQRS的基本理念是,您用来更新和读取数据的模型要相互分离是很自然的事情。上图描述了这种基本思想。
CQRS之所以在事件驱动型架构中如此受欢迎,是因为作为输入的领域事件与其所属的领域模型在结构上有所差异。以下面这个代表一个帐户的领域模型对象为例。
示例1.帐户整合
- {
- "createdAt":1481351048967,
- "lastModified":1481351049385,
- "userId":1,
- "accountNumber":"123456",
- "defaultAccount": true,
- "status":"ACCOUNT_ACTIVE"
- }
当某个服务想查询帐户时,就会使用该模型。那么,如果我们要将状态更新为ACCOUNT_SUSPENDED,该怎么办?通常,只需简单更新领域对象的状态字段即可。现在,如果我们想使用领域事件来更新状态,该怎么办?由于领域对象在结构上与事件不同,我们需要一个可将不同模型作为命令接受的API。
以下代码段是将帐户状态从ACCOUNT_ACTIVE转换为ACCOUNT_SUSPENDED的领域事件。
示例2.帐户事件
- {
- "createdAt":1481353397395,
- "lastModified":1481353397395,
- "type":"ACCOUNT_SUSPENDED",
- "accountNumber":"123456"
- }
要处理此领域事件并将更新应用到查询模型,我们必须有接受命令的API。该命令将包含领域事件的模型,并使用模型来处理对帐户查询模型的更新。
将命令模型与查询模型相分离是对CQRS最简单的解释。我们如今常见的复杂性更多地与实施类型有关,将模式应用到微服务时尤为如此。
CQRS和微服务
如果CQRS与微服务相结合,毫不夸张地说,情况就变得有点复杂了。我们来看看使用Spring Boot实施CQRS的“简单”微服务是什么样。
上图是CQRS模式实施的简略图示。图中,我们将一个微服务分为命令端、查询端和事件处理器,这三个部分可以相互独立地部署。
命令端
本示例中的命令端提供了REST API,可接受通过HTTP发送的请求。请求采取命令的形式,可以驱动对微服务所拥有的领域数据的状态更改。简单来说,对领域数据的任何写入都将以命令形式从API请求流出,处理导致数据库发生更改的操作。