icql

分布式事务

分布式环境下,一组任务,要么全部成功,要么全部失败



解决方案一:2pc

1)定义

2PC(2 prepare commit)两阶段提交协议,是将整个事务流程分为两个阶段

(1)准备阶段(prepare phase) (2)提交阶段(commit phase)

2)实现:DTP/XA协议

DTP/XA(Distributed Transaction Processing The XA Specification),基于实现DTP/XA协议的数据库的分布式事务,强一致性

(1)AP应用程序:是事务发起和结束的地方 (2)RM资源管理器:主要负责管理每个数据库的连接数据源 (3)TM事务管理器:负责事务的全局管理,包括事务的生命周期管理和资源的分配协调等

两阶段具体过程:

(1)准备阶段(prepare phase) AP发起事务,TM通知所有的RM进行执行事务,但都没有提交 (2)提交阶段(commit phase) 如果准备阶段中的RM有失败的,TM通知所有的RM进行rollback 如果准备阶段中的RM全部成功,TM通知所有的RM进行commit 这个阶段TM会记录事务日志,此阶段一定成功

XA方案的问题:

(1)需要本地数据库支持XA协议(mysql、oracle目前是支持的) (2)资源锁需要等到两个阶段结束才释放,性能较差

3)实现:seata框架-AT模式

seata框架-AT模式,基于应用层实现的2pc分布式事务,需要部署seata server

(1)AP应用程序:是事务发起和结束的地方 (2)RM资源管理器:主要负责管理每个数据库的连接数据源 (3)TM事务管理器:业务层中用来开启/提交/回滚一个整体事务 (4)TC事务协调器:负责事务的全局管理,处理协调各个分支事务的回滚提交,seata server实现 (5)UNDO_LOG (回滚日志记录表):每个应用的业务库中创建这张表,用来保存业务数据在更新前后的数据快照,以便异常能随时回滚 (6)seata server数据持久化:可以选择db/redis/file db创建三张表:globalTable(持久化全局事务)、branchTable(持久化各提交分支的事务)、 lockTable(持久化各分支锁定资源事务)

两阶段具体过程:

(1)准备阶段(prepare phase) Seata拦截sql 查库保存before image 执行sql 保存after image 生成行锁(利用seata server的lockTable)

(2)提交阶段(commit phase) 如果全部成功,执行commit只需要清除准备阶段的快照undolog和行锁 如果有失败的,执行rollback,比较数据库当前数据和afate image是否一致,一致说明正常,回滚到before image,否则就是出现脏写需要人工处理

比较XA:

性能较好,第一阶段执行完就释放了本地资源

4)实现:tcc模式

2pc的一种实现,性能较好,但是业务侵入性太强,补偿性事务,需要保证confirm和cancel方法的幂等性,seata框架也支持这种模式

(1)try:做业务检查和资源预留 (2)confirm:确认提交 (3)cancel:业务执行错误需要回滚的状态下执行分支事务的业务取消,预留资源释放

两阶段具体过程:

(1)准备阶段(prepare phase) TM对每个RM做try操作,执行业务检查及资源预留 (2)提交阶段(commit phase) 如果try全部成功,TM会保证confirm成功(重试),做业务确认操作 如果try有失败的,TM会保证cancel成功(重试),实现一个与Try相反的操作即回滚操作

比较XA和AT:

可以支持非事务型的数据库 但是实现起来复杂,业务侵入强



解决方案二:可靠消息

事务发起方将消息发送给消息中间件,事务参与方从消息中间件中接收消息消费

可靠消息需要解决的问题:

(1)本地事务与消息发送的原子性问题 本地事务和消息发送要么一起成功,要么一起失败 (2)事务参与方必须能正确消费消息 成功消费消息,且消费消息要支持幂等(防止网络抖动)

1)本地消息表

业务操作和写入本地消息表在同一个事务保证原子性 定时线程拉取本地消息表数据发送消息,成功后删除,有可能重复发送 事务参与方根据业务唯一ID做消费消息幂等

2)RocketMQ事务消息

先发送事务消息,再执行业务操作 事务消息刚开始是一个中间状态,消费者不能消费 MQ等待生产者本地事务成功后通知,或者等待超时主动事务回查,判断是否更改消息状态 业务成功,消息状态改为可消费 业务失败,删除消息