【前言】
TCC
Try:尝试执行业务,完成所有业务检查(一致性),预留必要的业务资源(准隔离性)。
Confirm:确认执行业务,不再做业务检查。只使用Try阶段预留的业务资源,Confirm操作满足幂等性。
Cancel: 若业务执行失败,则取消执行业务并释放Try阶段预留的业务资源。
主业务服务:负责发起并完成整个业务活动。
从业务服务:是整个业务活动的参与方,实现 Try、Confirm、Cancel 操作,供主业务服务调用。
事务管理器:管理整个业务活动,包括记录事务状态,调用从业务服务的 Confirm/Cancel 操作等。
2PC和3PC都是数据库层面的操作,对于开发人员无感知;而TCC是业务层的操作,对开发人员来说具有较高的开发成本。
2PC是一个整体的长事务,是刚性事务;而TCC是一组本地短事务,是柔性事务;
2PC是全局锁定资源,所有参与者阻塞等待事务管理器的通知;而TCC的资源锁定在于Try操作,业务方可以灵活选择业务资源的锁定粒度。
应用可以自定义数据操作的粒度,降低了锁冲突,提升吞吐量。
应用侵入性强, Try、Confirm、Cancel 三个阶段都需要业务逻辑实现。
需要根据网络、系统故障等不同失败原因实现不同的回滚策略, 实现难度大,一般借助 TCC 开源框架,ByteTCC,TCC-transaction,Himly。
Saga
LLT(Long Live Transaction):由一个个本地事务组成的事务链。
本地事务:事务链由一个个子事务(本地事务)组成,LLT = T1+T2+T3+...+Ti。
补偿:每个本地事务 Ti 有对应的补偿 Ci。
正常情况:T1,T2,T3,...,Ti
异常情况:T1,T2,T3,..Ti,Ci,...C3,C2,C1
向后恢复(Backward Recovery):撤销掉之前所有成功子事务。如果任意本地子事务失败,则补偿已完成的事务。如异常情况的执行顺序T1,T2,T3,..Ti,Ci,...C3,C2,C1。
向前恢复(Forward Recovery):即重试失败的事务,适用于必须要成功的场景,该情况下不需要Ci。执行顺序:T1,T2,...,Tj(失败),Tj(重试),...,Ti。
原子性:Saga 协调器协调事务链中的本地事务要么全部提交,要么全部回滚。
一致性:Saga 事务可以实现最终一致性。
持久性:基于本地事务,所以这个特性可以很好实现。
在应⽤层⾯加⼊逻辑锁的逻辑。
Session 层⾯隔离来保证串⾏化操作。
业务层⾯采⽤预先冻结数据的方式隔离此部分数据。
业务操作过程中通过及时读取当前状态的⽅式获取更新。
Ti和Ci必须是幂等的。如向后恢复和向前恢复时候如果不是幂等操作会导致数据不一致。
Ci必须是能够成功的,如果无法成功则需要人工介入。
Ti->Ci和Ci->Ti的执行结果必须是一样的。
无法保证隔离性;
一阶段提交本地事务,无锁,高性能;
事件驱动模式,参与者可异步执行,高吞吐;
Saga 对业务侵入较小,只需要提供一个逆向操作的Cancel即可;而TCC需要对业务进行全局性的流程改造;
【通知型事务】
基于MQ自身的事务消息方案
基于DB的本地消息表方案
本地消息表
需要有一个消息表,记录着消息状态相关信息。
业务数据和消息表在同一个数据库,要保证它俩在同一个本地事务。
在本地事务中处理完业务数据和写消息表操作后,通过写消息到 MQ 消息队列。
消息会发到消息消费方,如果发送失败,即进行重试。
处理消息队列中的消息,完成自己的业务逻辑。
如果本地事务处理成功,则表明已经处理成功了。
如果本地事务处理失败,那么就会重试执行。
如果是业务层面的失败,给消息生产方发送一个业务补偿消息,通知进行回滚等操作。
本地消息表建设成本比较低,实现了可靠消息的传递确保了分布式事务的最终一致性。
本地消息表与业务耦合在一起,难于做成通用性,不可独立伸缩。
本地消息表是基于数据库来做的,而数据库是要读写磁盘IO的,因此在高并发下是有性能瓶颈的
MQ事务消息
事务发起方首先发送半消息到MQ;
MQ通知发送方消息发送成功;
在发送半消息成功后执行本地事务;
根据本地事务执行结果返回commit或者是rollback;
如果消息是rollback, MQ将丢弃该消息不投递;如果是commit,MQ将会消息发送给消息订阅方;
订阅方根据消息执行本地事务;
订阅方执行本地事务成功后再从MQ中将该消息标记为已消费;
如果执行本地事务过程中,执行端挂掉,或者超时,MQ服务器端将不停的询问producer来获取事务状态;
Consumer端的消费成功机制有MQ保证;
需要MQ支持半消息机制或者类似特性,在重复投递上具有比较好的去重处理;
具有比较大的业务侵入性,需要业务方进行改造,提供对应的本地操作成功的回查功能;
使用了数据库来存储事务消息,降低了对MQ的要求,但是增加了存储成本;
事务消息使用了异步投递,增大了消息重复投递的可能性;
最大努力通知
业务活动的主动方,在完成业务处理之后,向业务活动的被动方发送消息,允许消息丢失。
主动方可以设置时间阶梯型通知规则,在通知失败后按规则重复通知,直到通知N次后不再通知。
主动方提供校对查询接口给被动方按需校对查询,用于恢复丢失的业务消息。
业务活动的被动方如果正常接收了数据,就正常返回响应,并结束事务。
如果被动方没有正常接收,根据定时策略,向业务活动主动方查询,恢复丢失的业务消息。
用到的服务模式:可查询操作、幂等操作;
被动方的处理结果不影响主动方的处理结果;
适用于对业务最终一致性的时间敏感度低的系统;
适合跨企业的系统间的操作,或者企业内部比较独立的系统间的操作,比如银行通知、商户通知等;
总结
| 属性 | 2PC | TCC | Saga | 本地消息表 | 事务消息 | 尽最大努力通知 |
|---|---|---|---|---|---|---|
| 事务一致性 | 强 | 弱 | 弱 | 弱 | 弱 | 弱 |
| 复杂性 | 中 | 高 | 中 | 低 | 低 | 低 |
| 业务侵入性 | 小 | 大 | 小 | 中 | 中 | 中 |
| 使用局限性 | 大 | 大 | 中 | 小 | 中 | 中 |
| 性能 | 低 | 中 | 高 | 高 | 高 | 高 |
| 维护成本 | 低 | 高 | 中 | 低 | 中 | 中 |








