之前我有一篇文章,介绍了分布式事务最经典的七种解决方案,这里咱们从业务需要的角度,依据不同的业务场景,给出最适宜的解决方案。
当咱们采纳服务/微服务架构,对业务进行分拆解耦后,原先在一个单体内,应用本地数据库保障ACID的数据批改,因为跨了多个服务,就不再实用了,就须要引入分布式事务来保障新的原子性。
因为分布式事务计划,无奈做到ACID的保障,没有一种完满的计划,可能解决掉所有业务问题。因而在理论利用中,会依据业务的不同个性,抉择最适宜的分布式事务计划。
业务分类
上面是常见的几种业务分类,以及适宜的解决方案介绍
多个微服务组合成原子操作
有一类业务场景是须要把多个微服务组合成原子操作:假如您有一个流动业务,用户点击支付按钮后,会支付一张优惠券,和一个月的会员。优惠券和会员别离属于不同的服务,须要都被调用,不心愿呈现一个服务调用胜利,另一个因为网络或者其余故障导致没有胜利。
这个场景适宜可靠消息计划,能够应用rocketmq、rabbitmq等,发送给音讯队列的音讯,肯定要等收到队列接管确认,再返回应用程序。
本地事务+多个微服务组合为原子操作
有一类业务与前一种业务状况相似,但有一些差异:假如您有一个新用户注册胜利后,支付一张优惠券和一个月会员。如果注册不胜利,不心愿调用支付;只有注册胜利才支付。
这种状况,适宜本地音讯计划,或者事务音讯计划。这两种计划都能保障本地事务和音讯的原子性。
订单类对一致性要求较高的业务
订单交易类业务,波及资金、库存、优惠券等多个服务,实现一个订单,须要相干的各个服务组合成一个整体可回滚的事务。如果订单进行过程中金额先扣减,后续因为库存不够只能退款,把金额弥补加回来。在这个过程中用户看到了金额缩小,又金额变回来,体验很差。个别这类业务都会先冻结资金,如果订单能胜利,在扣减资金,不能胜利,则冻结资金,这样可能让资金信息对用户更敌对。
这种场景适宜TCC计划,能够在TCC的Try中冻结资金,Confirm中扣减资金,Cancel中冻结资金
一致性要求不高的可回滚业务
如果业务对事务中的一致性要求不高,容许用户看到中间状态,例如用户的积分数据等。
这种模式实用SAGA模式,SAGA比照与TCC,只有正向操作和逆向弥补操作,会更加简略
耗时较久的全局事务
耗时较旧的全局事务适宜可靠消息和SAGA,不适宜TCC和XA,因为大多数的XA和TCC实现,为了不便用户灵便的定义事务,通常把事务的进度保留在应用程序,一旦事务进行中应用程序解体,无奈往前进行下一步,只能回滚。
SAGA和可靠消息,把事务进度保留在数据库或音讯零碎中,任何一个组件长期的失败,都能够重试。其中如果整个事务是须要回滚的,那么适宜SAGA,不须要回滚的,适宜可靠消息
并发度较低的业务
如果业务并发度不高,事务有须要反对回滚,那么适宜XA计划。XA计划,除了并发不高,也还须要本地数据库能反对XA接口。这个计划的长处是,应用上较简略,比拟靠近本地事务
实际
下面介绍完各种业务类型,以及适宜的事务计划,通常状况下,您须要抉择适合的开源我的项目来施行技术计划。在分布式事务畛域,利用比拟宽泛的有DTM、SEATA、RocketMq
其中seata用Java开发,反对Java语言的接入,反对TCC、SAGA、XA、AT(相似XA,性能更高,但有脏回滚)
RocketMq用Java开发,反对各类语言的接入,仅反对可靠消息、事务音讯模式
这里重点介绍DTM,它用GO开发,基于HTTP协定,反对多种语言接入,反对TCC、SAGA、XA、可靠消息、事务音讯模式。
可靠消息例子
咱们拿第一个最简略的业务场景“多个微服务组合成原子操作”来看DTM是如何解决问题的
假如支付优惠券和会员的处理函数别离是:ObtainCoupon和ObtainVip,那么解决支付逻辑的处理函数(用Go做示例)只用这么写:
msg := dtmcli.NewMsg(DtmServer,gid). Add(Busi+"/ObtainCoupon", req). Add(Busi+"/ObtainVip", req) err := msg.Submit()
dtm收到客户端提交的音讯后,会保障ObtainCoupon和ObtainVip被调用,如果任何一个呈现失败,会一直重试,直到胜利。
如果您采纳的是rocketmq计划,那么您须要做一下几个步骤:
- 发送"支付"的音讯给队列
- 生产"支付”的音讯,而后调用ObtainCoupon和ObtainVip,而后确认音讯已胜利生产
比照dtm和rocketmq的计划,dtm仅须要简略的几行代码即可(dtm也提供http的接口,能够用任何语言间接发http申请),清晰简略。而rocketmq计划,波及较多队列的常识,要做的工作较多
SAGA例子
假如咱们有一个积分兑换课程的业务,一方面积分不属于十分外围的资产,另一方面兑换课程可能呈现课程已领有权限,则须要回滚,因而该业务属于“一致性要求不高的可回滚业务“。
咱们采纳SAGA计划来解决这个问题,来看看DTM的解决形式,代码大抵如下:
saga := dtmcli.NewSaga(DtmServer, gid). Add(Busi+"/AdjustIntegral", Busi+"/AdjustIntegralRevert", req). Add(Busi+"/AuthCourse", Busi+"/AuthCourseRevert", req) saga.WaitResult = true err := saga.Submit()
dtm收到客户端提交的saga事务之后,会按顺序调用AdjustIntegral,AuthCourse,如果函数返回谬误要求回滚,dtm则会调用AuthCourseRevert,AdjustIntegralRevert进行回滚。
如果您没有采纳dtm计划,那么您能够采纳SEATA的SAGA,波及比拟多的背景常识,接入较简单。
更多的例子
您能够拜访https://github.com/yedf/dtm ,外面有很多的分布式事务例子
多种模式并存
如果您的理论我的项目,波及分布式事务的场景较多,可能须要应用SEATA+Rocketmq,会比较复杂。而DTM提供了一站式的解决方案,对常见的各种业务场景都提供了便捷的反对。
小结
dtm作为一个新衰亡的分布式事务框架,提供了弱小的性能,以及简略易用的接口,极大的简化了微服务架构下,分布式事务的应用。
上面是dtm与seata的次要个性比照:
个性 | DTM | SEATA | 备注 |
---|---|---|---|
反对语言 | Golang、python、php、c# 及其他 | Java | dtm可轻松接入一门新语言 |
异样解决 | 子事务屏障主动解决 | 手动解决 | dtm解决了幂等、悬挂、空弥补 |
TCC事务 | ✓ | ✓ | |
XA事务 | ✓ | ✓ | |
AT事务 | ✗ | ✓ | AT与XA相似,性能更好,但有脏回滚 |
SAGA事务 | 简略模式 | 状态机简单模式 | dtm的状态机模式在布局中 |
事务音讯 | ✓ | ✗ | dtm提供相似rocketmq的事务音讯 |
通信协议 | HTTP | dubbo等协定,无HTTP | dtm后续将反对grpc类协定 |
dtm的我的项目地址为https://github.com/yedf/dtm ,欢送大家拜访、试用、点亮star