接上篇,我们回收了规模驱动的开拓方法,利用了充血模子,享受了他的长处,可是也不得不面临他带来的漏洞。这个漏洞在漫衍式的微处事架构下面又被放大。
事务一致性
事务一致性的问题在Monolithic下面不是大问题,在微处事下面却是很致命,我们回首一下所谓的ACID原则
在单体处事和干系型数据库的时候,我们很容易通过数据库的特性去完成ACID。可是一旦你凭据DDD拆分聚合根-微处事架构,他们的数据库就已经分分开了,你就要独立面临漫衍式事务,要在本身的代码内里满意ACID。
对付漫衍式事务,各人一般会想到以前的JTA尺度,2PC两段式提交。我记恰当年在Dubbo群内里,根基每周城市有人询问Dubbo啥时候支撑漫衍式事务。实际上按照漫衍式系统中CAP原则,当P(分区容忍)产生的时候,强行追求C(一致性),会导致(A)可用性、吞吐量下降,此时我们一般用最终一致性来担保我们系统的AP本领。虽然不是说放弃C,而是在一般环境下CAP都能担保,在产生分区的环境下,软件开发,我们可以通过最终一致性来担保数据一致。
例:
在电贸易务的下订单冻结库存场景。需要按照库存环境确定订单是否成交。
假设你已经回收了漫衍式系统,这里订单模块和库存模块是两个处事,别离拥有本身的存储(干系型数据库),
在一个数据库的时候,一个事务就能搞定两张表的修改,劳务派遣管理系统,可是微处事中,就没法这么做了。
在DDD理念中,一次事务只能改变一个聚合内部的状态,假如多个聚合之间需要状态一致,那么就要通过最终一致性。订单和库存明明是分属于两个差异的限界上下文的聚合,这里需要实现最终一致性,就需要利用事件驱动的架构。
事件驱动实现最终一致性
事件驱动架构在规模工具之间通过异步的动静来同步状态,有些动静也可以同时宣布给多个处事,在动静引起了一个处事的同步后大概会引起别的动静,事件会扩散开。严格意义上的事件驱动是没有同法式用的。
例子:
在订单处事新增订单后,订单的状态是“已开启”,然后宣布一个Order Created事件到动静行列上
库存处事在吸收到Order Created 事件后,将库存表格中的某sku减掉可销售库存,增加订单占用库存,然后再发送一个Inventory Locked事件给动静行列
订单处事吸收到Inventory Locked事件,将订单的状态改为“已确认”
有人问,假如库存不敷,锁定不乐成怎么办? 简朴,库存处事发送一个Lock Fail事件, 订单处事吸收后,把订单置为“已打消”。
好动静,我们可以不消锁!事件驱动有个很大的优势就是打消了并发,所有请求都是列队进来,这对我们实施充血模子有很大辅佐,我们可以不需要本身来打点内存中的锁了。打消锁,行列处理惩罚效率很高,事件驱动可以用在高并发场景下,好比抢购。
是的,用户体验有改变,用了这个事件驱动,用户的体验有大概会有改变,好比本来同步架构的时候没有库存,就顿时汇报你条件不满意无法下单,不会生成订单;可是改了事件机制,订单是当即生成的,很大概过了一会系统通知你订单被打消掉。 就像抢购“小米手机”一样,几十万人在列队,排了好久汇报你没货了,来日诰日再来吧。假如但愿用户当即获得功效,可以在前端想步伐,在BFF(Backend For Frontend)利用CountDownLatch这样的锁把后端的异步转成前端同步,虽然这样BFF耗损较量大。