分布式事务常见方案
(1) 存储层拆分
最典型的就是分库分表,一般来说,当单表容量到达千万级,就要考虑数据库拆分,从单一数据库编程多个分库和多个分表,在业务中需要进行跨表或者跨表更新,同时要保证数据的一致性,就会产生分布式事务问题
(2) 服务层拆分
服务层拆分就是业务上进行拆分,从集中式变为分布式,几个操作有一个失败,那么整体的大操作就会失败,此时需要分布式事务来保证
2PC
二阶段提交,引入协调者概念----1.准备阶段 :协调者询问参与者事务是否执行成功,参与者发回事务执行结果。2.提交阶段:如果事务在每个参与者上都执行成功,事务协调者发送通知让参与者提交事务;否则,协调者发送通知让参与者回滚事务。
存在的问题:
单点故障:第一阶段完成后,出现宕机,参与者一直阻塞
同步阻塞:准备就绪后,参与者中的资源一直处于阻塞状态,直到提交完成后,释放资源
3PC
三阶段提交协议(3PC,Three-phase commit protocol)是在 2PC之上扩展的提交协议,主要是为了解决两阶段提交协议的阻塞问题,从原来的两个阶段扩展为三个阶段,增加了超时机制。
TCC
将事务分为Try,Confirm/Cancel,两个阶段,每个阶段的逻辑由业务进行控制,避免了长事务,代码侵入性比较长
TM:Transaction Manager,事务管理器,负责整个TCC事务的协调控制
TC:Transaction Coordinator,事务协调人
**Try:**在try阶段,参与者尝试执行本地事务,并对全局事务预留资源。如果try阶段执行成功,参与者会返回一个成功标识,否则会返回一个失败标识。
**Confirm:**如果所有参与者的try阶段都执行成功,则协调者通知所有参与者提交事务,那么就要执行confirm阶段,这时候参与者将在本地提交事务,并释放全局事务的资源。
**Cancel:**如果任何一个参与者在try阶段执行失败,则协调者通知所有参与者回滚事务。那么就要执行cancel阶段。
缺点:存在悬挂事务问题:在执行中一些事务成功了,而一些子事务失败了,导致整个事务无法回滚
空回滚问题:TCC在try阶段,有的参与者成功了,有的参与者失败了,这时候需要所有参与者回滚,但是对于没有try成功的事务来说,本次回滚试一次空回滚,需要在业务中对空回滚进行识别
SAGA
Saga 事务核心思想是将长事务拆分为多个本地短事务并依次正常提交,如果所有短事务均执行成功,那么分布式事务提交;如果出现某个参与者执行本地事务失败,则由 Saga 事务协调器协调根据相反顺序调用补偿操作,回滚已提交的参与者,使分布式事务回到最初始的状态。Saga 事务基本协议如下:
(1)每个 Saga 事务由一系列幂等的有序子事务(sub-transaction) Ti 组成。
(2)每个 Ti 都有对应的幂等补偿动作 Ci,补偿动作用于撤销 Ti 造成的结果。
与TCC事务补偿机制相比,TCC有一个预留(Try)动作,相当于先报存一个草稿,然后才提交;Saga事务没有预留动作,直接提交。
本地消息表
通过消息日志的形式来异步执行,日志可以存储在本地,数据库或者是消息队列中,再通过业务规则进行处理
基于mq实现
是对本地消息表的一种封装.功能原理如下:
- Half Message:暂时不能被消费,producer把消息发送给broker,但是该消息被标记为不能被投递,producer开始执行本地事务,当producer对他进行二次确认后(commit或者rollback),也就是commit后,消息才能被消费,如果是rollback,消息被永久删除
- 事务状态回查:可能因为网络原因,producer一直没有对该消息进行确认,那么broker服务器回定时扫描这些半消息,主动找producer查询该信息的状态
Seata
AT:Seata会自动提交和回滚分支事务, 无需开发人员额外的编码,适应比较简单的场景,只需要引入@GlobalTransaction注解即可
TCC:需要编写业务try,confirm,cancel操作,处理分支事务的预提交,适用于对数据一致性要求高的场景。采用的是基于业务逻辑的补偿机制,将整个分布式事务分解成若干个子事务
SAGA:使用一系列的局部事务,依次来达到全局一致性
XA:上面三者都是实现最终一致性,但是XA是实现强一致性