MySQL XA能够实现数据层的分布式事务,解决多个MySQL操作的事务问题,但是我们还需要上次应用层保证指令执行的原子性

可以考虑使用TCC,利用TCC来实现业务层面操作的事务,就可以从数据层面到业务层面,全面理解如何实现分布式事务了

我们拿一个实例来举例,我们需要实现一个订票系统,我们需要考虑一种问题

假如,我从深圳飞往北京,没有直达的机票,需要先定深圳的航班,从深圳飞往上海,然后从上海飞往北京

那么就要保证,要么全部订购成功,要么全不成功,如何操作呢?

图片

那么整体的订票事务,就是一个TCC的流程

什么是TCC,TCC其中包含着两个阶段,预留 确认/撤销,2阶段提交

Try 预留,二阶段提交协议,将系统需要的资源预留,锁定,确保确认操作一定执行成功

Confrim 确认,二阶段提交中,提交执行操作类似,系统最终执行的操作

Cancel,撤销,二阶段提交协议中的回滚操作,系统将撤销预留的而资源,撤销已经执行的预留操作对系统产生的影响

二阶段提交协议和TCC的目标,都是为了实现分布式事务,那么这两者就基本互通,我们来看看TCC的细节

我们拿着上面的场景来看,我们假设深圳航空,上海航空分别都提供了机票预留,确认,撤销三个接口

那么我们的整体事务的操作如下

订票系统调用2个航空公司的机票预留接口,向2个航空公司进行try请求

图片

如果都预留了,就可以进入确认阶段,进行执行确认操作,直接订票

图片

但如果有机票没有预留成功,那怎么办呢,订票系统就需要撤销接口来撤销订票请求

图片

这样就基本实现了

那么如何通过TCC来保证指令执行的原子性呢?

假设我们具有多个操作,我们要保证这些操作可以组合成事务来执行,那么如何做到的呢?

图片 假设这三个操作分别为

1.生成指定URL的图片存储

2.调用内部系统1的接口,禁用指定域名的访问权限

3.通过mysql XA来更新多个数据的数据记录

我们分别使用TCC来解决这个问题,我们给每个操作,实现了各自的预留,确认,撤销操作

对于1操作,

预留操作,生成指定的页面的图片,存储到本地

确认操作,更新操作1状态为完成

撤销操作,删除本地存储的图片

操作3是利用了MySQL XA来更改多个mysql数据库中数据记录,实现数据更新的事务,

预留操作:执行XA START和XA END来准备好事务分支操作,并且调用CA PREPARE,执行二阶段提交协议的提交请求阶段

确认操作,调用XA commit来执行确认操作

撤销操作,调用XA ROLLBACK执行回滚操作,释放Try阶段预留的资源

那么,确认操作可以预留操作的下个操作,撤销而是撤销已经锁定的资源,

图片

那么,操作1 2 3 的预留操作已经执行结束,如果预留都成功了,将执行确认操作,继续向下执行,如果预留操作只是部分执行成功,将进行撤销操作,取消预留操作对系统的影响,可以执行指令执行的原子性了

我们说了TCC,和如何使用TCC来实现分布式事务

那么TCC是一个业务层面的分布式事务协议,XA是数据层面的分布式事务协议,是TCC和XA的最大区别

TCC和业务耦合紧密,在实际场景使用时候,需要根据场景特点和业务逻辑来设计相应的预留,确认,撤销操作,相比MySQL XA,有一定的编程开发工作量

本质上TCC是一种设计模式,是一种理念,没有和任何技术耦合,不受限于任何技术,对所有有需求的技术方案都是适用的

最后TCC是交给业务代码之中编码实现的,所以 TCC可以跨数据库,跨业务,满足不同业务场景下的事务需求

而且,TCC的每一个操作对于数据库来说,都是一个本地数据库的事务,那么当操作结束的时候,本地数据库的事务就执行完成了,所以相关的数据库资源也就释放了,避免了数据层面的二阶段提交的长时间锁定资源,导致性能下降的问题

本章问题,就是通过TCC解决了指令执行的原子性,为什么呢?

在执行的过程中,TCC利用了二阶段提交的思想,既能够锁定成功,就相当于收到了锁定的确认操作,只有在所有的锁定确认收到了,才可以继续执行Confrim操作,在执行Confrim操作的时候,就不允许失败的存在,即使挂了,也会有后来人再上线的时候重新顶替上去

发表评论

邮箱地址不会被公开。 必填项已用*标注