然后,因为我们的架构是基于ES的,所以,针对新增或修改聚合根的Command,老是会产生响应的范畴事宜(Domain Event)。我们接下来的要做的工作就是要先持久化事宜,再分发这些事宜给所有的外部事宜订阅┞愤。大年夜家知道,聚合根有生命周期,在它的生命周期里,会经历各类事宜,而事宜的产生总有肯定的时光次序。所以,为了明白哪个事宜先产生,哪个事宜后产生,我们可以对每个事宜设置一个版本号,即version。聚合根第一个产生的事宜的version为1,第二个为2,以词攀类推。然后聚合根本身也有一个版本号,用于记录当缁ぴ己的版本是什么,它每次产生下一?事宜时,也能根据本身的版本号推导出下一?要产生的事宜的版本号是什么。比如聚合根当前的版本号为5,那下一?事宜的版本号则为6。经由过程为每个事宜设计一个版本号,我们就能很便利的实现聚合根产闹事宜时的并发控制了,因为一个聚合根弗成能产生两个版本号一样的事宜,如不雅出现这种情况,那解释必定是出现并发冲突了。也就是必定是出现了同一个聚合根同时被两个Command修改的情况了。所以,要实现事宜持久化的幂等处理,也很好做了,就是db中的事宜表,对聚合根ID+聚合根当前的version建独一索引。如许就能在db层面,确保Event持久化的幂等处理。别的,对于事宜的持久化,我们也可以像秒杀那样,实现Group Commit。就是Command产生的事宜不消立马持久化,而是可以先积聚到必定的量,比如50个,然后再一次性Group Commit所有的事宜。然后事宜持久化完成后,再修改每个聚合根的状况即可。如不雅Group Commit事宜时遇参预发冲突(因为某个聚合根的事宜的版本号有反复),则退回为单个一个个持久化事宜即可。为什么可以宁神的┞封样做?因为我们已经根本做到确保一个聚合根同一时刻只会被一个Command修改。如许就能根本包管,这些Group Commit的事宜也不会出现版本号冲突的情况。所以,大年夜家是否认为,很多设计其实是一环套一环的。Group Commit何时出发?我认为可以只要知足两个前提了就可以触发:1)某个准时的周期到了就可以触发,这个准时周期可以根据本身的营业场景进行设备,比如每隔50ms触发一次;2)要Commit的事宜达到某个最大年夜值,即每批可以持久化的事宜个数的最大年夜值,比如每50个事宜为一批,这个BatchSize也须要根据实际营业场景和你的存储db的机能综合测试评估来获得一个最合适的值;何时可以应用Group Commit?我认为只有是在并发异常高,当单个持久化事宜碰到机能瓶颈时,才须要应用。不然反而会降低事宜持久化的及时性,Group Commit进步的是高并发下单位时光内持久化的事宜数。目标是为了降低应用和DB之间交互的次数,大年夜而削减IO的次数。不知不觉就说到了最开端说的那3点机能优化中的,尽量削减IO了,呵呵。
Event花费时的幂等处理
CQRS架构简介
CQRS架构是基于消息驱动的,所以我们要尽量避免消息的反复花费。不然,可能会导致某个消息被反复花费而导致最终数据无法一致。对于CQRS架构,我认为重要推敲三个环节的消息幂等处理。
Command的幂等处理
大年夜家知道,全部CQRS架构中,Command,Event的产生以及处理是异常频繁的,数据量也是异常大年夜的。那若何包管这几步幂等处理的高机能呢?对于Command的幂等处理,如不雅对机能请求不是很高,那我们可以简单应用关系型DB即可,比如Sql Server, MySQL都可以。要实现幂等处理,只须要把主键设计为CommandId即可。其他不须要额外的独一索引。所以这里的机能瓶颈相当于是对单表做大年夜量insert操作的最大年夜TPS。一般MySQL数据库,SSD硬盘,要达到2W TPS应当没什愦问题。对于这个表,我们根本只有写入操作,不须要攫取操作。只有是在Command插入碰到主键冲突,然后才可能须要有时根据主键攫取一下已经存在的Command的信息。然后,如不雅单表数据量太大年夜,那怎么办,就是分表分库了。这就是最开端谈到的,要避开海量数据这个原则了,我想就是经由过程sharding避开大年夜数据来实现绕过IO瓶颈的设计了。不过一旦涉及到分库,分表,就又涉及到根据什么分库分表了,对于存储Command的表,我认为比较简单,我们可以先根据Command的类型(相当于根据营业做垂直拆分)做第一级路由,然后雷同Command类型的Command,根据CommandId的hashcode路由(程度拆分)即可。如许就能解决Command经由过程关系型DB存储的机能瓶颈问题。其实我们还可以经由过程风行的基于key/value的NoSQL来存储,比如可以选择本地运行的leveldb,或者支撑分布式的ssdb,或者其他的,具体选择哪个,可以结合本身的营业场景来选择。总之,Command的存储可以有很多选择。
关于EventStore的机能瓶颈分析
关于CQRS(Command Query Responsibility Segration)架构,大年夜家应当不会陌生了。简单的说,就是一个体系,大年夜架构上把它拆分为两部分:敕令处收成写请求)+萌芽处收成读请求)。然后读写两边可以用不合的架构实现,以实现CQ两端(即Command Side,简称C端;Query Side,简称Q端)的分别优化。CQRS作为一个读写分别思惟的架构,在数据存储方面,没有做过多的束缚。所以,我认为CQRS可以有不合层次的实现,比如:
- CQ两端数据库共享,CQ两端只是在上层代码上分别;这种做法,带来的好处是可以让我们的代码读写分别,更好保护,且没有CQ两端的数据一致性问题,因为是共享一个数据库的。我小我认为,这种架构很实用,既兼顾了数据的强一致性,又能让代码好保护。
- CQ两端数据库和上层代码都分别,然后Q的数据由C端同步过来,一般是经由过程Domain Event进行同步。同步方法有两种,同步或异步,如不雅须要CQ两端的强一致性,则须要用同步;如不雅能接收CQ两端数据的最终一致性,则可以应用异步。采取这种方法的架构,小我认为,C端应当采取Event Sourcing(简称ES)模式才有意义,不然就是本身给本身找麻烦。因为如许做你会发明会出现冗余数据,同样的数据,在C端的db中有,而在Q端的db中也有。和膳绫擎第一种做法比拟,我想不到什么好处。而采取ES,则所有C端的最新数据全部用Domain Event表达即可;而要萌芽显示用的数据,则大年夜Q端的ReadDB(关系型数据库)萌芽即可。
推荐阅读
因为这些技巧的合营之处是它们生成本身的特点,也许我们应当称之为无特点建模的阶段(Era of Featureless Modeling)。你仍然不得不应用已知的标注实例进行练习,然则你不必在列中填入预定>>>详细阅读
本文标题:谈一下关于CQRS架构如何实现高性能
地址:http://www.17bianji.com/lsqh/36039.html
1/2 1