vlambda博客
学习文章列表

一周技术学习笔记(第62期)-CQRS是”有点不同“的读写分离

对数据的操作一共就四种。
图自https://time.geekbang.org/dailylesson/detail/100056986
 
我们把这四种操作,又划分为两类,读和写
 
为了提升对数据库的性能,我们又做了读写分离。
 
一周技术学习笔记(第62期)-CQRS是”有点不同“的读写分离
 
上面这个图是我们最为熟悉的读写分离场景了,另外我们也熟悉了这样的方法有两个不好地方。
 
1、写库有单点故障问题。
2、数据库同步有延迟。
 
TIP:读写分离,更主要是为了减少读操作的压力。
 
有了数据库层面的”归纳“:CRUD->读、写,那么在应用层面我们可以做点啥呢。
可以继续”归纳“:CRUD->读、写->查询、命令。
 
这里将查询和命令分开,也就是我们要说的CQRS(Command Query Responsibility Segregation)模型,命令与查询职责分离
 
一周技术学习笔记(第62期)-CQRS是”有点不同“的读写分离
图自https://time.geekbang.org/dailylesson/detail/100056986
 
这样,我们在应用层面就可以抽象成如下模样。
 
一周技术学习笔记(第62期)-CQRS是”有点不同“的读写分离
图自https://time.geekbang.org/dailylesson/detail/100056986
 
到这里,估计你看出来了,没错,CQRS是”有点不同“的读写分离
 
下面,我们主要说下”有点不同“。
 
当我们说传统的读写分离的时候,锚点侧重在数据库层面,当我们说CQRS的时候,锚点侧重在应用层面。
 
在应用层面,我们一直需要考虑的一个问题是如何正确的划分操作的边界和职责,这里说的操作也可指服务操作,你可以联想微服务中的环境。
 
将操作的职责划分清楚,有一个基本的设计原则,单一职责,你也可以理解CQRS的核心设计基础来自单一职责。
 
将操作的职责划分清楚,还有一个可以借鉴的设计原则,比单一职责粒度稍微粗一些,就是我们常说的分离关注点,你也可以理解CQRS是分离关注点设计原则的应用场景之一。
 
CQRS 把数据的变更和查询拆开了,各有各的数据模型。
 
TIP:写存储可以用MySQL这样的关系型数据库,而查询存储则可以使用Elasticsearch作为存储。命令-查询职责分离(CQRS)模式是一种应用于这种场景的通用模型,它显式地将系统中的读(查询)和写(命令)进行分离。
 
静态上,拆分了这两块的代码,使各自可以采用不同的技术栈,做针对性的调优。命令模型负责数据的变更,并把最新数据同步给查询模型(有时候类似数据异构)。
 
动态上,切分了流量,能够更灵活的做资源分配,处理数据逻辑的时候,查询模型根据自己的想法来安排数据,想怎么用就怎么用
 
好处是可以让查询更加自由,放飞自我,更快的满足多变的业务需求。坏处是增加了架构的复杂度,有时候可能需要维护很多个查询模型,另外还有数据同步带来的问题。
 
我们上面提到了数据异构。
 
那么体现数据异构的地方在哪里呢,可以看一看下面这幅图。
 
一周技术学习笔记(第62期)-CQRS是”有点不同“的读写分离
 
在这里,事件处理器消费这些事件,以便构建合适的查询模型。具体的实现方式当然可以使用RabbitMQ或者Kafka这样的中间件。
 
比如,在线投资交易平台系统中,有customer服务、order服务、fee服务,现在要汇总所有账户的订单手续费,并且要按照不同的属性,订单类型、资产类别、支付方式,来进行分类汇总。仅仅在单个服务层面是不可能完成这个功能的,因为不管是customer服务、order服务还是fee服务,它们都不拥有全量的数据来支持按照那些属性过滤,每个服务只有一部分数据
 
这个时候采用CQRS的设计方法,我们就可以构建出一个CustomerOrder的查询服来组装上面那个查询诉求。
 
一周技术学习笔记(第62期)-CQRS是”有点不同“的读写分离
 
查询服务通过其他服务发出的事件消息来组建复合型的数据视图。
 
既然谈到了事件,也许此时此刻你可能联想到了DDD中的事件溯源模式,因为它们确实有点哪儿相似或者哪儿有点关联。
 
事件溯源机制有两个核心的问题:
 
1、如何生成领域事件?
2、生成领域事件后,如何获取领域对象的状态信息?
 
上面关于事件的两张图里面已经可以”窥一斑“了。多少是回答了这两个问题的,有事件发射器和接收器,也有状态对象的获取。实际上CQRS模式可以和事件溯源模式天然的进行整合。
 
 
图自网络
 
最后,引用《微服务实战》这本书的一段话,结尾。
 
想要全面理解CQRS是比较困难的,它需要大家采用一种不同于之前处理常规的CRUD API时的思维方式。但是,在微服务应用中,CQRS确实很有用的。如果应用得当,CQRS有助于确保查询功能的性能和可用性,即便数据和功能是隶属于不同服务的不同数据存储上的。
 
另外下面是关于微服务相关的一些知识点,来自《微服务实战》这本书。
 
(1)在跨服务的交互中实现ACID特性是很困难的,微服务需要采用不同的方式来实现一致性。
(2)类似两阶段提交这样的协调方案会引入加锁操作,扩展性不好。
(3)基于事件的架构可以解除各个独立组件之间的耦合,并为微服务应用的业务逻辑和查询的可扩展性打下基础。
(4)倾向于高可用,而非一致性,这会使得架构的可扩展性更强。
(5)Saga是由一组消息驱动的、独立的本地事务组成的全局操作。它们通过补偿操作来回滚错误的状态,以实现一致性。
(6)在构建反映现实世界环境的微服务时,预见失败场景并做好准备是非常重要的一部分内容,操作的隔离性反而没那么至关重要。
(7)我们通常通过组合多个API的结果来实现跨多个微服务的查询功能。
(8)高效的复合型查询应该采用CQRS模式来实现一套独立的读数据模型,特别是在那些查询模式需要采用另一种数据存储系统时。
 
 
提问1,如果的业务是涉及金融交易的部分,需要保证主从数据库的强一致性,但是MySQL复制又不能保证强一致性,这样的情况下该怎么办呢。
 
业务层上只有2\3PC提交协议,数据层上只有Paxos算法。
 
 
学习参考资料(文中配图来自此处):
https://time.geekbang.org/column/article/7045
https://time.geekbang.org/dailylesson/detail/100056986
《微服务实战》
 
 

----END----

这里记录,我每周碰到的,或想到的,引起触动,或感动的,事物的思考及笔记。不见得都对,但开始思考记录总是好的。


欢迎分享、点赞、在看,一键三连