Akka系列(八):Akka persistence设计理念之CQRS

这一篇文章主要是讲解Akka persistence的核心设计理念,也是CQRS(Command Query Responsibility Segregation)架构设计的典型应用,就让我们来看看为什么Akka persistence会采用CQRS架构设计。

CQRS

很多时候我们在处理高并发的业务需求的时候,往往能把应用层的代码优化的很好,比如缓存,限流,均衡负载等,但是很难避免的一个问题就是数据的持久化,以致数据库的性能很可能就是系统性能的瓶颈,我前面的那篇文章也讲到,如果我们用数据库去保证记录的CRUD,在并发高的情况下,让数据库执行这么多的事务操作,会让很多数据库操作超时,连接池不够用的情况,导致大量请求失败,系统的错误率上升和负载性能下降。

既然这样,那我们可不可借鉴一下读写分离的思想呢?假使写操作和同操作分离,甚至是对不同数据表,数据库操作,那么我们就可以大大降低数据库的瓶颈,使整个系统的性能大大提升。那么CQRS到底是做了什么呢?

我们先来看看普通的方式:

image.png

我们可以看出,我们对数据的请求都是通过相应的接口直接对数据库进行操作,这在并发大的时候肯定会对数据库造成很大的压力,虽然架构简单,但在面对并发高的情况下力不从心。

那么CQRS的方式有什么不同呢?我们也来看看它的执行方式:

image.png

乍得一看,似乎跟普通的方式没什么不同啊,不就多了一个事件和存储DB么,其实不然,小小的改动便是核心理念的转换,首先我们可以看到在CQRS架构中会多出一个Event,那它到底代表着什么含义呢?其实看过上篇文章的同学很容易理解,Event是我们系统根据请求处理得出的一个领域模型,比如一个修改余额操作事件,当然这个Event中只会保存关键性的数据。

很多同学又有疑问了,这不跟普通的读写分离很像么,难道还隐藏着什么秘密?那我们就来比较一下几种方式的不同之处:

1.单数据库模式
  • 写操作会产生互斥锁,导致性能降低;
  • 即使使用乐观锁,但是在大量写操作的情况下也会大量失败;
2.读写分离
  • 读写分离通过物理服务器增加,负荷增加;
  • 读写分离更适用于读操作大于写操作的场景;
  • 读写分离在面对大量写操作的情况下还是很吃力;
3.CQRS
  • 普通数据的持久化和Event持久化可以使用同一台数据库;
  • 利用架构设计可以使读和写操作尽可能的分离;
  • 能支撑大量写的操作情况;
  • 可以支持数据异步持久,确保数据最终一致性;

从三种方式各自的特点可以看出,单数据库模式的在大量读写的情况下有很大的性能瓶颈,但简单的读写分离在面对大量写操作的时候也还是力不从心,比如最常见的库存修改查询场景:

image.png

我们可以发现在这种模式下写数据库的压力还会很大,而且还有数据同步,数据延迟等问题。

那么我们用CQRS架构设计会是怎么样呢:

image.png

首先我们可以业务模型进行分离,对不同的查询进行分离,另外避免不了的同一区间数据段进行异步持久化,在保证数据一致性的情况下提升系统的吞吐量。这种设计我们很少会遇到事务竞争,另外还可以使用内存数据库(当然如果是内存操作那就最快)来提升数据的写入。(以上的数据库都可为分布式数据库,不担心单机宕机)

那么CRQS机制是怎么保证数据的一致性的呢?

从上图中我们可以看出,一个写操作我们会在系统进行初步处理后生成一个领域事件,比如a用户购买了xx商品1件,b用户购买了xx商品2件等,按照普通的方式我们肯定是直接将订单操作,库存修改操作一并放在一个事务内去操作数据库,性能可想而知,而用CQRS的方式后,首先系统在持久化相应的领域事件后和修改内存中的库存(这个处理非常迅速)后便可马上向用户做出反应,真正的具体信息持久可以异步进行,当然若是当在具体信息持久化的过程中出错了怎么办,系统能恢复正确的数据么,当然可以,因为我们的领域事件事件已经持久化成功了,在系统恢复的时候,我们可以根据领域事件来恢复真正的数据,当然为了防止恢复数据是造成数据丢失,数据重复等问题我们需要制定相应的原则,比如给领域事件分配相应id等。

使用CQRS会带来性能上的提升,当然它也有它的弊端:

  • 使系统变得更复杂,做一些额外的设计;
  • CQRS保证的是最终一致性,有可能只适用于特定的业务场景;

Akka Persistence 中CQRS的应用

通过上面的讲解,相信大家对CQRS已经有了一定的了解,下面我们就来看看它在Akka Persistence中的具体应用,这里我就结合上一篇文章抽奖的例子,比如其中的LotteryCmd便是一个写操作命令,系统经过相应的处理后得到相应的领域事件,比如其中LuckyEvent,然后我们将LuckyEvent进行持久化,并修改内存中抽奖的余额,返回相应的结果,这里我们就可以同时将结果反馈给用户,并对结果进行异步持久化,流程如下:

image.png

可以看出,Akka Persistence的原理完全是基于CQRS的架构设计的,另外Persistence Actor还会保存一个内存状态,相当于一个in memory数据库,可以用来提供关键数据的存储和查询,比如前面说到的库存,余额等数据,这部分的设计取决于具体的业务场景。

阅读Akka Persistence相关源码,其的核心就在于PersistentActor接口中的几个持久方法,比如其中的

def persist[A](event: A)(handler: A ⇒ Unit): Unit

def persistAll[A](events: immutable.Seq[A])(handler: A ⇒ Unit): Unit 

等方法,它们都有两个参数,一个是持久化的事件,一个是持久化后的后续处理逻辑,我们可以在后续handler中修改Actor内部状态,向外部发送消息等操作,这里的模式就是基于CQRS架构的,修改状态有事件驱动,另外Akka还可以在系统出错时,利用相应的事件恢复Actor的状态。

总结

总的来说,CQRS架构是一种不同于以往的CRUD的架构,所以你在享受它带来的高性能的同时可能会遇到一些奇怪的问题,当然这些都是可以解决的,重要的是思维上的改变,比如事件驱动,领域模型等概念,不过相信当你理解并掌握它之后,你便会爱上它的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容