在面对复杂的业务应用程序(其中读写有单独的要求)时,CQRS是一种有效的解决方案。
例如,写服务希望在RDB中以规范化形式来维护数据模型,但读服务可以将模型改为Document数据库中的文档。但是要了解CQRS并不是很容易。他里面包括了读服务,写服务,事件,命令,DDD,事件源,最终一致性。而且通用实现CQRS的方式是创建两个服务,并且他们之间的通讯是以事件的方式来进行。
我们项目中的CQRS实现
为了实现CQRS,我们使用了Axon框架。我们选CQRS框架的时候,Axon被认定为使用起来很简单方便并且他能很好的支持Spring boot框架,所以这就是Axon框架被采用的原因。

我们最终为写和读创建了两个单独的服务。这两个服务通过RabbitMQ来连接。
写服务
写服务处理所有的更新操作。我们不会试图去说服开发人员,让他们觉得写请求就是真实的命令(Command)。Controller 是负责从请求中获取数据并创建Command并将其发布到CommandGateway中。
Controller 和Command 处理器之间是异步的。Command 处理器是通过加载聚合(Aggregates),并执行对应的业务逻辑然后将事件发布到RabbitMQ来处理命令。与此同时该事件还会被存储在事件存储(Event Store)中。在该实现中,事件存储充当我们的唯一的真相来源。
读服务
读服务处理所有的读请求,在这里他没有任务的业务处理。写入的数据会被一个事件处理器通过监听RabbitMQ的事件进行逻辑处理并写入到数据库(仓储)中。
当然你可以选择关系性数据库或者MongoDB做为读服务的数据库,这个看你自己的爱好。我们希望开发人员实现的是一个优化过的读模型。它们只是存储数据并无需额外的操作来提高读取性能。
正如你所见,这是一个非常简单的例子。我们拆分了读和写两个服务。但是为什么我们最后失败了呢?
为什么我们失败了?
异步操作
当我们引入CQRS后,开发人员抱怨最多的就是:"我们怎么去更新UI界面,我们不知道我们操作的结果是否是成功的。" 这是一个好问题,我们平时主要接触的都是同步操作。 没关系,我们一开始就使用它进行编码。 因为很容易推理。 您可以获取请求的完整流程。
为什么我们要EDA架构(事件驱动架构)中使用异步操作呢?最简单的原因是想提高响应速度。EDA和异步操作并无任务关系。我们可以在不使用异步操作的情况下实现CQRS。
太大的工作量
开发人员经常抱怨的第二个东西是:"要完成基于CQRS的微服务我们需要双倍的工作量。" 这就是事实,我们的研发人员不得不创建两个服务来代替以前的一个服务:写服务,读服务。我们就是以这种方式来实现的CQRS。如果我们找到更简单的创建他们的方法,那么我们可以减少完成CQRS所需的时间。 我们开始创建一个Maven原型,该原型为基于CQRS的微服务生成框架,以减少开发人员的工作量。
在所有的微服务中使用CQRS
我们告诉研发人员将CQRS应用到每个微服务中。我们认为整个系统都应该是CQRS系统,至少在当时我们是这样理解的。最后的结果是导致不可管理的复杂度。这个最大的错误是我们在错误的理解CQRS并去实现他。Greg Young 在一个视频中说到(我记得)我们必须找到可以从使用CQRS中受益的领域。它可能是系统的一小部分。如果我们无法获得商业价值,那么就没必要去应用这些东西。CQRS一定是由业务驱动来产生的。
很小的微服务
我们不能说微服务应该有多小才算合适,但是我们可以确定它的边界。我们可以使用DDD和Bounded Context来确定微服务的边界。在CQRS中我们称为聚合。聚合是一堆相关的域对象。比如"订单"和"订单项"。我们把"订单"和"订单项"是一个事件。当我们保存"订单"时会把"订单项"一起保存,而不会分开保存。当我们无法识别Aggregate时,最终会将其拆分为单个微服务。这就增加了CQRS的复杂性。当您收到保存订单的请求时,你该怎么办?
这个问题也我们也遇上了。
越小的微服务意味着会有更多的微服务。由于我们把CQRS应用到了所有的微服务上,所以最后我们的微服务数量是正常的两倍。这太难以管理了,最后我们采取了一些措施来避免这些问题。
这次失败的主要原因是在实现方式上并且大多数原因和CQRU并不相关。我从中学到的是,我们必须了解微服务和CQRS的核心概念,然后才能将它们柔和在一起使用。
原文地址:
https://medium.com/faun/why-we-failed-implementing-cqrs-in-microservice-architecture-5c39a2d0b2dd
网友评论