微服务架构如今很热,处处能够看到各大互联网公司的微服务实践的分享总结。可是,我今天的分享和微服务没有关系,但愿能够带给你们一些新的东西。数据库
若是必定要说微服务和CQRS架构的关系,那我以为微服务是一种边界思惟,微服务的目的是为了从业务角度拆分(职责分离)当前业务领域的不一样业务模块到不一样的服务,每一个微服务之间的数据彻底独立,它们之间的交互能够经过SOA RPC调用(耦合比较高),也能够经过EDA 消息驱动(耦合比较低)。架构
微服务架构和CQRS架构的关系:每一个微服务内部,咱们能够用CQRS/ES架构来实现,也能够用传统三次架构来实现。并发
首先,咱们须要先理解DDD中的聚合、聚合根这两个概念。负载均衡
聚合,它经过定义对象之间清晰的所属关系和边界来实现领域模型的内聚,并避免了错综复杂的难以维护的对象关系网的造成。聚合定义了一组具备内聚关系的相关对象的集合,咱们把聚合看做是一个修改数据的最小原子单元。框架
聚合根,每一个聚合都有一个根对象,根对象管理聚合内的其余子对象(实体、值对象);聚合之间的交互都是经过聚合根来交互,不能绕过聚合根去直接和聚合下的子实体进行交互。异步
上面的例子中,Car、Wheel、Position、Tire四个对象构成一个聚合,其中Car是聚合根;Customer也是聚合根,Customer不能直接访问Car下的Tire(子实体),而是只能经过聚合根Car来访问。分布式
上面表达了一个关于聚合的一致性设计原则:聚合内的数据修改,是ACID强一致性的;跨聚合的数据修改,是最终一致性的。遵照这个原则,可让咱们最大化的下降并发冲突,从而最大化的提升整个系统的吞吐。微服务
In-Memory的意思是指整个系统中的全部的聚合根对象都活在内存。而不是像咱们平时那样,用到的时候才从DB获取对象,而后再作修改,再保存回去。线程
在In-Memory的架构下,当要修改某个聚合根的状态时,它已经在内存,咱们能够直接拿到该对象的引用,且框架会尽可能保证聚合根对象的状态就是最新的。聚合根是在内存中的最小计算单元,每一个聚合内部都封装了业务规则,并保证数据的强一致性。设计
上图我是挪用了以前比较或的LMAX架构中的一个图,表达的思想就是in-memory架构。其中Business Logic Processor就是中央业务逻辑处理器,内部承载了大量在机器内存中活着的聚合根对象;
不保存对象的最新状态,而是保存对象产生的全部事件;
经过事件溯源(Event Sourcing,ES)获得对象最新状态;
接下来,咱们再来看一下什么是事件溯源。
一个对象从建立开始到消亡会经历不少事件,之前咱们是在每次对象参与完一个业务动做后把对象的最新状态持久化保存到数据库中,也就是说咱们的数据库中的数据是反映了对象的当前最新的状态。而事件溯源则相反,不是保存对象的最新状态,而是保存这个对象所经历的每一个事件,全部的由对象产生的事件会按照时间前后顺序有序的存放在数据库中。能够看出,事件溯源的这种作法是更符合事实观的,由于它完整的描述了对象的整个生命周期过程当中所经历的全部事件。
那么,事件到底如何影响一个领域对象的状态的呢?很简单,当咱们在触发某个领域对象的某个行为时,该领域对象会先产生一个事件,而后该对象本身响应该事件并更新其本身的状态,同时咱们还会持久化在该对象上所发生的每个事件;这样当咱们要从新获得该对象的最新状态时,只要先建立一个空的对象,而后将和该对象相关的全部事件按照事件发生前后顺序从先到后再所有应用一遍便可还原获得该对象的最新状态,这个过程就是所谓的事件溯源。
另外一方面,由于是用事件来表示对象的状态,而事件是只会增长不会修改。这就能让数据库里的表示对象的数据很是稳定,不可能存在DELETE或UPDATE等操做。由于一个事件就是表示一个事实,事实是不能被磨灭或修改的。这种特性可让领域模型很是稳定,在数据库级别不会产生并发更新同一条数据的问题。
CRUD:DB的记录可变,能够增删改查
ES:没有更新、删除,只有Append Event,不可变
经过上面这个图,你们应该能够更直观的理解事件溯源和传统CRUD思想的区别
Actor模型,这个概念你们应该都了解。Actor模型的核心思想是:
对象直接不会直接调用来通讯,而是经过发消息来通讯。
每一个Actor都有一个Mailbox,它收到的全部的消息都会先放入Mailbox中,而后Actor内部单线程处理Mailbox中的消息。从而保证对同一个Actor的任何消息的处理,都是线性的,无并发冲突。从全局上来看,就是整个系统中,有不少的Actor,每一个Actor都在处理本身Mailbox中的消息,Actor之间经过发消息来通讯。
Akka框架就是实现Actor模型的并行开发框架,而且Akka框架融入了聚合、In-Memory、Event Sourcing这些概念。
Actor很是适合做为DDD聚合根。Actor的状态修改是由事件驱动的,事件被持久化起来,而后经过Event Sourcing的技术,还原特定Actor的最新状态到内存。
上图表达的是事件驱动的架构的思想。Node表示节点,每一个节点负责处理逻辑;Event表示消息,节点之间经过消息进行通讯。消息经过分布式消息队列如RocketMQ,Equeue进行通讯。
不一样于SOA架构,EDA架构是pub-sub模式;Node1处理完逻辑后产生消息,Node2订阅消息并进行处理,Node1不知道Node2的存在;
最终一致性原则,Node1,Node2之间的数据一致性经过MQ最终保证一致;
如何保证最终一致性(消息链不会断开):
A. MQ保证消息不丢;
B. 任何一个Node要保证本身彻底处理完后才发送ACK给MQ;
C. 每一个Node作到对任何消息处理的幂等性;
整个架构具备全部分布式MQ所带来的优势:如异步解耦、削峰、下降整个系统的总体部署成本;
上图是一个面向Topic的分布式MQ的逻辑架构图,采用这种架构的MQ有:Kafka,RocketMQ,EQueue。
Producer发送消息到某个Topic的某个Queue;
消息都存储在Broker上;
Consumer从Broker拉取消息进行消费,并支持消费者负载均衡;