了解CQRS
在传统的三层架构中,通常都是通过数据访问层来修改或者查询数据,一般修改和查询使用的是相同的实体。在一些业务逻辑简单的系统中可能没有什么问题,但是随着系统逻辑变得复杂,用户增多,这种设计就会出现一些性能问题。虽然在数据库层面可以做一些读写分离的设计,但在业务上如果在读写方面混合在一起的话,仍然会出现一些问题。
命令查询职责分离(Command Query Responsibility Segregation,CQRS)旨在从业务上分离命令和查询的行为。从而使得逻辑更加清晰,便于对不同部分进行针对性的优化。
那么,到底什么是CQRS?使用CQRS能带来什么好处呢?下面为你揭晓。
CQRS概述
CQRS最早来自Betrand Meyer在Object-Oriented SoftwareConstruction本文中提到的一种命令查询分离(Command QuerySeparation,CQS)的概念。其基本思想在于,任何一个对象的方法可以分为两大类。
·命令(Command):不返回任何结果(void),但会改变对象的状态。
·查询(Query):返回结果,但是不会改变对象的状态,对系统没有副作用。
根据CQS的思想,任何一个方法都可以拆分为命令和查询两部分,比如在Java中POJO对象中的属性操作,通常会有getter/setter方法。
public class City {
private String cityName;
public String getCityName() {
return cityName;
}
public void setCityName(String cityName) {
this.cityName = cityName;
}
}
根据CQS的定义,这里的setCityName就是命令,getCityName就是查询。
命令和查询分离使得我们能够更好地把握对象的细节,能够更好地理解哪些操作会改变系统的状态。
CQRS是由CQS模式进一步改进的一种简单模式。它由Greg Young在CQRS,Task Based UIs,Event Sourcing agh!这篇文章中提出。CQRS使用分离的接口将数据查询操作和数据修改操作分离开来,这也意味着在查询和更新过程中使用的数据模型也是不一样的,这样读和写逻辑就隔离开来了。观察下面的CustomerService例子。
void makeCustomerPreferred(CustomerId)
Customer getCustomer(CustomerId)
CustomerSet getCustomersWithName(Name)
CustomerSet getPreferredCustomers()
void changeCustomerLocale(CustomerId, NewLocale)
void createCustomer(Customer)
void editCustomerDetails(CustomerDetails)
CustomerService是传统的服务接口定义模式,混杂了数据查询操作和数据修改操作。
在此基础上应用CQRS之后,将产生两种服务:
CustomerWriteService和CustomerReadService。
其中,CustomerWriteService就是命令。
void makeCustomerPreferred(CustomerId)
void changeCustomerLocale(CustomerId, NewLocale)
void createCustomer(Customer)
void editCustomerDetails(CustomerDetails)CustomerReadService代表查询。
Customer getCustomer(CustomerId)
CustomerSet getCustomersWithName(Name)
CustomerSet getPreferredCustomers()
CQRS与Event Sourcing的关系
CQRS与Event Sourcing经常放在一起使用。在CQRS中,查询直接通过方法查询数据库,然后通过DTO将数据返回。命名是通过发送Command实现,首先由CommandBus处理特定的Command,然后由Command将特定的Event发布到EventBus上,最后EventBus使用特定的Handler来处理事件,执行一些诸如新增、删除、更新等操作。这里,所有与Command相关的操作都通过Event实现。这样我们可以通过记录Event来记录系统的运行历史记录,并且能够方便地回滚到某一历史状态。而Event Sourcing就是用来进行存储和管理事件的。
CQRS好处
与传统的代码组织方式相比,应用CQRS模式看上去改动并不是很大,只是将方法分为了命令和查询两大阵营。但是应用CQRS可以带来比较大的益处,特别是可以令系统设计人员认识到它们在处理命令和查询时是不同的架构属性。例如,它允许我们以不同的方式承载CustomerWriteService和CustomerReadService这两种服务。例如,我们可以在25台服务器上承载读取服务,在两台服务器上承载写入服务。命令和查询的处理基本上是不对称的,而是根据实际的需要来进行相应的扩展。
总结来说,使用CQRS可以带来以下好处。·使得查询变得更加简单高效。
·分工明确,可以负责不同的部分。
·能够提升系统的性能、可扩展性和安全性。
·逻辑清晰,能够看到系统中的哪些行为或者操作导致了系统的状态变化。
·可以从数据驱动(Data-Driven)转到任务驱动(Task-Driven)以及事件驱动(Event-Driven)。