关于幂等处理的机能问题的思虑
关于CommandStore的机能瓶颈分析
经由过程膳绫擎的分析,我们知道Event的存储独一须要的是AggregateRootId+Version的独一索引,其他就无任何请求了。那如许就和CommandStore一样好办了。如不雅也是采取关系型DB,那只要用AggregateRootId+Version这两个作为结合主键即可。然后如不雅要分库分表,我们可以先根据AggregateRootType做第一级垂直拆分,即把不合的聚合根类型产生的事宜分开存储。然后和Command一样,雷同聚合根产生的事宜,可以根据AggregateRootId的hashcode来拆分,同一个AggregateRootId的所有事宜都放一路。如许既能包管AggregateRootId+Version的独一性,又能包管数据的程度拆分。大年夜而让全部EventStore可以无穷制程度伸缩。当然,我们也完全可以采取基于key/value的NoSQL来存储。别的,我们萌芽事宜,也都是会肯定聚合根的类型以及聚合根的ID,所以,这和路由机制一向,不会导致我们无法知道当前要萌芽的聚合根的事宜在哪个分区上。
设计存储时的重点推敲点
在设计command, event的存储时,我认为重要推敲的应当是进步整体的吞吐量,而不是寻求单机存储的机能。因为假如我们的体系平均每秒产生1W个事宜,那一天就是8.64亿个事宜。已经是很大年夜的数据量。所以,我们必须要对command, event这种进行分片。比如我们设计864个表,那每个表天天产生100W笔记录,这是在可以接收典范围内。然后,我们一旦分了864个表了,肯定会把它们分布在不呵9依υ?理数据库上。如许就是多个物理数据库同时供给存储办事,可以整体进步存储的吞吐量。我小我比较偏向于应用MySQL来存储即可,因为一方面MySQL是开源的,各类分库分表的成熟做法比较多。另一方面,关系型数据库比拟Mongodb这种,本身更熟悉,能更好的┞菲握。比如数据扩容筹划可以本身做,不像MongoDB这种,固然它都帮我们搞定了大年夜数据存储,但一旦出了问题,也许本身无法掌控。另一方面,关于RT,即单条数据存储时的响应时光,这个我认为不管是关系型数据库照样NoSQL,最终的瓶颈都是在磁盘IO。NoSQL之所以这么快,无非就是异步刷盘;而关系型DB不是很快,因为它要包管数据的落地,要包管数据的更高等其余靠得住性。所以,我认为,要在包管数据不会损掉的情况下,尽量进步RT,可以推敲应用SSD硬盘。另一方面,我认为因为我们已经做了分库分表了,所以单个DB的压力不会太大年夜,所以一般局域网内的RT也不会延迟很大年夜,应当可以接收。
聚合根的内存模式(In-Memory)
懂得过actor的人应当也知道actor也是全部集群中就一个实例,然后每个actor本身都有一个mailbox,这个mailbox用于存放当前actor要处理的所有的消息。只要办事器赓续电,那actor就一向存活在内存。所以,In-Memory模式也是actor的一个设计思惟之一。像之前很轰动的国外的一个LMAX架构,号称每秒单机单核可以处理600W订单,也是完全基于in-memory模式。不过LMAX架构我认为只要作为进修即可,要大年夜范围应用,照样有很多问题要解决,老外他们应用这种架构来处理订单,也是基于特定场景的,并且对编程(代码质量)和运维的请求都异常高。具体有兴趣的可以去搜一下相干材料。
关于in-memory架构,设法主意是好的,经由过程将所稀有据都放在内存,所有持久化都异步进行。也就是说,内存的数据擦?鲱新的,db的数据是异步持久化的,也就是某个时刻,内存中有些数据可能还没有被持久化到db。当然,如不雅你说你的法度榜样不须要持久化数据,那另当别论了。那如不雅是异步持久化,重要的问题就是宕机恢复的问题了。我们看一下akka框架是怎么持久化akka的状况的吧。
- 多个消息同时发送给actor时,全部会先放入该actor的mailbox里列队;
- 然后actor单线程大年夜mailbox次序花费消息;
- 花费一个后产闹事宜;
- 持久化事宜,akka-persistence也是采取了ES的方法持久化;
- 持久化完成后,更新actor的状况;
- 更新状况完成后,再处理mailbox中的下一?消息;
大年夜膳绫擎的过程,我们可以看出,akka框架本质上也实现了避免资本竞争的原则,因为每个actor是单线程处理它的mailbox中的每个消息的,大年夜而就避免了并发冲突。然后我们可以看到akka框架也是先持久化事宜之后,再更新actor的状况的。这解释,akka采取的也叫保守的方法,即必须先确保数据落地,再更新内存,再处理下一?消息。真正幻想的in-memory架构,应当是可以忽视持久化,当actor处理完一个消息后,急速修改本身的状况,然后急速处理下一?消息。然后actor产生的事宜的持久化,美满是异步的3就镣是不消等待持久化事宜完成后再更新actor的状况,然后处理下一?消息。
我认为,是不是异步持久化不重要,因为既然大年夜家都要面对一个问题,就是要在宕机后,恢复actor的状况,那持久化事宜是弗成避免的。所以,我也是认为,事宜不必异步持久化,完全可以像akka框架那样,产生的事宜先同步持久化,完成后再更新actor的状况即可。如许做,在宕机恢复actor的状况到最新时,就只要简单的大年夜db获取所有事宜,然后经由过程ES获得actor最新状况即可。然后如不雅担苦衷宜同步持久化有机能瓶颈,那这个老是弗成避免,这块不做好,那全部体系的机能就上不去,所以我们可以采取SSD,sharding, Group Commit, NoSQL等办法,优化持久化的机能即可。当然,如不雅采取异步持久化事宜的方法,确切能大年夜大年夜进步actor的处理机能。然则要做到这点,还须要有一些前提的。比如要确保全部集群一一个actor只有一个实例,不克不及有两个一样的actor在工作。因为如不雅出现这种情况,那这两个一样的actor就会同时产闹事宜,导致最后事宜持久化的时刻必定会出现并发冲突(事宜版本号雷同)的问题。但要包管急群众一个actor只有一个实例,是很艰苦的,因为我们可能会动态往集群中增长办事器,此时必定会有一些actor要迁徙到新办事器。这个迁徙过程也很复杂,一个actor大年夜本来的办事器迁徙到新的办事器,意味着要先停止原办事器的actor的工作。然后还要把actor再新办事器上启动;然后原办事器上的actor的mailbox中的消息还要发给新的actor,然后后续可能还在发给原actor的消息也要转发到新的actor。然后新的actor重启也很复杂,因为要确保启动之后的actor的状况必定是最新的,而我们知道这种纯in-memory模式下,事宜的持久化时异步的,所以可能还有一些事宜还在消息队列,还没被持久化。所以重启actor时还要检查消息队列中是否还有未花费的事宜。如不雅还有,就须要等待。不然,我们恢复的actor的状况就不是最新的,如许就无法包管内存数据是最新的┞封个目标,如许in-memory也就掉去了意义。这些都是麻烦的技巧问题。总之,要实现真正的in-memory架构,没那么轻易。当然,如不雅你说你可以用数据网格之类的产品,无分布式,那也许可行,不过这是别的一种架构了。
推荐阅读
因为这些技巧的合营之处是它们生成本身的特点,也许我们应当称之为无特点建模的阶段(Era of Featureless Modeling)。你仍然不得不应用已知的标注实例进行练习,然则你不必在列中填入预定>>>详细阅读
本文标题:谈一下关于CQRS架构如何实现高性能
地址:http://www.17bianji.com/lsqh/36039.html
1/2 1