点赞再看,养成习惯,微信搜索「小大白日志」关注这个搬砖人。
文章不定期同步公众号,还有各种一线大厂面试原题、我的学习系列笔记。
分布式事务的四种处理措施
在分布式系统中实现分布式事务,它有多个本地事务组成。事务一般遵守ACID(原子性、一致性、隔离性、持久性),但分布式事务很难ACID都满足。一般实现分布式事务有4种方法:2PC、TCC、本地消息表、RocketMQ消息事务
2PC
- 定义:顾名思义,这个过程有两步=P+C:做一些准备工作来锁定资源,除了提交事务之外啥事都做了(P)->提交或者回滚事务(C);
一般会有一个事务协调者、多个事务参与者,首先事务协调者会群发“准备命令”给各个事务参与者,各个事务参与者除了“commit”命令之外准备工作都做完了,然后发送“准备成功”给事务协调者 -> 事务协调者群发“commit”命令让每个事务参与者提交各自本地的事务;
- 特点:
- 假如在第一阶段就有参与者返回“准备失败”,则协调者群发“回滚”命令让各参与者回滚;
- 假如第二阶段失败了(1)如果是某个参与者“commit”失败,则不断重试直到成功(2)如果是某个参与者“回滚”失败,也是不断重试
- 假如协调者很久没收到某个参与者的“准备成功”命令,则等待一定的时间后就认为该参与者准备失败,群发“回滚”命令让其他参与者回滚操作
- 弊端:各个事务参与者做完准备工作之后必须阻塞等待其他参与者完成才能“commit”;系统对事务协调者依赖过大,一旦协调者发生故障不能用,那么整个系统分布式事务将不可用
TCC
- 定义:T=try=预留资源,C=confirm=预留资源成功则提交事务,C=cancel=预留资源失败则回滚事务;TCC方案有一个事务协调者(和2PC一样)、多个'TCC服务',一个事务协调者协调多个'TCC服务'的事务提交和回滚,所以每个'TCC服务'都要实现try/confirm/cancel方法;首先事务协调者会调用所有'TCC服务'的try方法去预留资源,所有'TCC服务'预留成功则返回成功标识,事务协调者再调用所有'TCC服务'的confirm方法提交事务,若有一个'TCC服务'预留失败则调用cancel回滚事务,如下:
- 特点:
- 允许空回滚:事务协调者发出的try指令由于网络原因而丢包,进而触发cancel指令,那么各'TCC服务方'就只会收到cancel指令而造成空回滚,所以'TCC服务方'应该支持空回滚,如下
- 防悬挂控制:事务协调者发出的try指令由于网络原因一直未到达各个'TCC服务方',从而事务协调者一直未收到响应而触发了cancel回滚指令,此时'TCC服务方'先收到cancel指令执行了空回滚,而后收到延迟的try指令,但'TCC服务方'应该拒绝延迟的try指令,如下
- 允许空回滚:事务协调者发出的try指令由于网络原因而丢包,进而触发cancel指令,那么各'TCC服务方'就只会收到cancel指令而造成空回滚,所以'TCC服务方'应该支持空回滚,如下
本地消息表
假如现在有两个业务操作需要执行,在本地消息表中有一条对应的消息状态代表它们是否都执行成功:第一个业务操作之后,接着执行下一个业务操作,如果下一个业务操作成功,则返回结果给第一个业务去修改它们对应的某条消息状态为'成功';如果第一个或下一个业务操作失败,则它们对应本地消息表中的某条消息状态改为'失败';对于本地消息表中失败状态的消息,会有定时器去定时扫描它们并重新发起对应的业务操作
RocketMQ消息事务
有一个发送方会提前发送一个'半消息'给RocketMQ的broker(负责消息的接收、存储、发送),broker接到后返回成功标识给发送方,然后发送方执行本地事务,执行成功再发送commit给broker,然后订阅方从broker中读到commit命令代表执行完自身的业务后可以提交自身事务,提交完再回头消费这条'commit命令消息';如果发送方执行本地事务失败则发送rollback给broker,'rollback命令'和'半消息'对订阅者都是不可见的,订阅方都收不到这两种消息,也就不需要往下执行订阅方自身的事务;另外发送方需要提供一个反查询事务接口给RocketMQ的broker,以便broker在持续没有收到发送方的commit/rollback命令时,可以反查询出发送方的事务执行结果进而判断是否向订阅者提供'commit命令消息'
OK,如果文章哪里有错误或不足,欢迎各位留言。
创作不易,各位的「三连」是二少创作的最大动力!我们下期见!