转载请注明出处:https://oldnoop.tech/c/190.html
tcc
主要基于两阶段的思想,把事务分为 try 和 confirm或cancel的2个阶段
在try阶段,完成业务检查并预留资源
如果try阶段成功,则运行confirm提交事务
如果try阶段不成功,则运行cancel回滚事务
分布式事务
一个上层的业务操作可能调用多个分布式应用的业务操作,
可以把发起的主业务操作当做主事务,
调用多个应用的业务操作当做子事务,
这样将一个分布式事务问题,变成多个事务的一起提交或者一起回滚的操作
进而将每个业务抽象为一个参与者,每个事务可能包含多个参与者,每个事务的提交和回滚变成 多个事务参与者的提交和回滚操作
这里需要一个事务管理器TransactionManager,负责
启动 主事务,传播发起子事务,
添加参与者到事务(即业务操作,包括confirm操作和cancel操作),
提交事务(执行事务中所有参与者的confirm操作),
回滚事务(执行事务中所有参与者的cancel操作)
事务需要抽象为一个对象Transaction,事务参与者也抽象为一个对象Participant,每个Participant包含了confirm和cancel操作
实现方式
每个事务,包括主事务和子事务, 都有2张表
1张表记录事务信息(这个一个临时表,记录事务id,每个事务有各自的事务id,状态,重试次数等),
1张表记录业务操作日志表(包括具体的业务数据,全局业务id,每个事务的操作日志表的全局业务id一致,状态等)
try阶段
主事务启动
先通过事务管理器记录一条事务数据(生成一个全局事务id),这时候状态是try,
然后执行主业务操作,并写一条业务操作日志,需要记录全局业务id,状态是try,完成预留资源操作
最后调用分布式操作接口,会将主事务的业务操作日志的全局业务id传递给子事务
启动各个子事务
执行子事务的try操作,
子事务也是先记录一条事务数据,这个时候状态是try,
然后执行子业务操作,并写一条业务操作日志,需要记录全局业务id,状态是try,完成预留资源操作
confirm阶段
如果try阶段都执行成功,则执行confirm操作,即提交事务
依次执行主事务和各个子事务的confirm操作,
并将业务操作日志状态置为confirm,
同时删除主事务和子事务的事务数据
cancel阶段
如果try阶段失败,即不是所有的try都成功,则执行cancel操作,即回滚事务
依次执行主事务和各个子事务的cancel操作,
并将业务操作日志状态置为cancel,
同时删除主事务和子事务的事务数据
异常情况分析
try阶段
如果写事务数据失败,整个try阶段失败
接下来写业务操作和业务操作日志失败,整个try阶段失败
都会进入cancel阶段
confirm阶段
如果主事务confirm操作失败,
或者主事务confirm操作成功,有子事务confirm操作失败
可以使用最大努力型事务的思想,进行重试
如果事务执行成功,事务表是临时表,最终会删除事务数据
这时候使用定时器,不断的扫描事务表,如果定时器扫描事务表,有数据并且状态try,且重试次数没有达到最大值,则发起重试
这里也是结合分布式的CAP/BASE原理,满足最终一致性
如果在极端情况下,重试多次后仍然时候,事务表中有数据,可以提供页面操作,人工干预发起重试,
事务的confirm操作如何重试调用
事务表中会保存,事务对象的序列化后的内容,重试的时候,会反序列化得到事务对象,执行事务对象中的各个业务参与者的confirm操作
confirm操作需要实现幂等性
各事务的confirm操作需要实现幂等性,即对一个相同的操作,执行多次,结果是一样的,
有可能出现的情况是,confirm操作成功,但是删除事务临时表数据的操作失败,定时器一样会再次发起重试,
这个就是借助各事务中的业务日志表来实现的,根据全局业务id查询,如果存在且状态已经为confirm,就直接返回
cancel阶段
如果主事务cancel操作失败,
或者主事务canel操作成功,有子事务canel操作失败,
和confirm阶段类似,采用最大努力型事务的思想,
进行重试,反序列化事务对象,执行事务对象中的各个业务参与者的cancel操作,达到最终一致性
TCC优缺点分析
优点主要是柔性事务,最终一致性的方案,补偿方案可采用异步操作,效率比较高
缺点主要是实现复杂,各分布式业务必须实现try,confirm,cancel的操作,给编码造成一定难度