前不久,看到博客园一位园友写了一篇文章,其间的观念是,要想高功用,需求尽量:避开网络开支(IO),避开海量数据,避开资本抢夺。对于这3点,我觉得很有道理。所以也想谈一下,CQRS架构下是怎样完结高功用的。
对于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(联系型数据库)查询即可。
我觉得要完结高功用,能够谈的东西还有许多。下面我想要点说说我想到的一些规划思路:
避开资本抢夺
秒杀活动的比方剖析
我觉得这是很首要的一点。啥是资本抢夺?我想即是多个线程一同修正同一个数据。就像阿里秒杀活动一样,秒杀开抢时,许多人一同抢一个商品,致使商品的库存会被并发更新减库存,这即是一个资本抢夺的比方。通常假设资本竞赛不激烈,那无所谓,不会影响功用;可是假设像秒杀这种场景,那db就会抗不住了。在秒杀这种场景下,许多线程需求一同更新同一条记载,进而致使MySQL内部许多线程堆积,对效劳功用、安稳性形成很大损伤。那怎样办呢?我记得阿里的丁奇写过一个共享,思路即是当MySQL的效劳端多个线程一同修正一条记载时,能够对这些修正恳求进行排队,然后对于InnoDB引擎层,即是串行的。这么排队后,不管上层运用发过来多少并行的修正同一行的恳求,对于MySQL Server端来说,内部老是会聪明的对同一行的修正恳求都排队处理;这么就能保证不会有并发发作,然后不会致使线程糟蹋堆积,致使数据库功用下降。这个计划能够见下图所示:
如上图所示,当许多恳求都要修正A记载时,MySQL Server内部会对这些恳求进行排队,然后一个个将对A的修正恳求提交到InnoDB引擎层。这么看似在排队,实践上会保证MySQL Server不会死掉,能够保证对外供给安稳的TPS。
可是,对于商品秒杀这个场景,还有优化的空间,即是Group Commit技能。Group Commit即是对多个恳求合并为一次操作进行处理。秒杀时,咱们都在购买这个商品,A买2件,B买3件,C买1件;本来咱们能够把A,B,C的这三个恳求合并为一次减库存操作,即是一次性减6件。这么,对于A,B,C的这三个恳求,在InnoDB层咱们只需求做一次减库存操作即可。假定咱们Group Commit的每一批的size是50,那即是能够将50个减操作合并为一次减操作,然后提交到InnoDB。这么,将大大进步秒杀场景下,商品减库存的TPS。可是这个Group Commit的每批巨细不是越大越好,而是要依据并发量以及效劳器的实践状况做测验来得到一个最优的值。经过Group Commit技能,依据丁奇的PPT,商品减库存的TPS功用从本来的1.5W进步到了8.5W。
从上面这个比方,咱们能够看到阿里是怎样在实践场景中,经过优化MySQL Server来完结高并发的商品减库存的。可是,这个技能通常人还真的不会!由于没多少人有才能去优化MySQL的效劳端,排队也不行,更甭说Group Commit了。这个功用并不是MySQL Server自带的,而是需求自个完结的。可是,这个思路我想咱们都能够学习。