共计 2918 个字符,预计需要花费 8 分钟才能阅读完成。
之前我有一篇文章,介绍了分布式事务最经典的七种解决方案,这里咱们从业务需要的角度,依据不同的业务场景,给出最适宜的解决方案。
当咱们采纳服务 / 微服务架构,对业务进行分拆解耦后,原先在一个单体内,应用本地数据库保障 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