目录
名词解析 XA模式 两个阶段
优点
缺点两段提交协议(2PC) 过程
优点
缺点:三段提交协议(3PC) 过程TCC 方案(补偿事务) 三个阶段
优点
缺点本地消息表 可靠消息最终一致性方案 过程最大努力通知方案
分布式事务
名词解析
全局事务: 整个分布式事务
分支事务: 分布式事务中包含的每个子系统的事务
最终一致性: 各分支事务分别执行并提交,如果有不一致的情况,想办法补偿恢复,达到数据的最终一致性
强一致性: 各事务执行完业务不要提交,等待彼此结束,之后统一提交或回滚
XA模式
强一致性分阶段事务模式,牺牲了一定的可用性,无业务侵入。
两个阶段
- 第一阶段由事务协调者向RM(XA模式下一般由数据库实现)发起事务准备请求,RM执行完毕之后,并不直接提交事务,而是将执行的结果告知事务协调者。
- 第二阶段由事务协调者判断RM的返回结果,如果分支事务都成功了,向RM发起提交请求,RM执行事务提交并返回已提交请求。但是,如果在事务执行过程中有一个失败了,事务协调者则会回滚所有已执行事务。
优点
- 事务强一致性,满足ACID原则
- 常用数据库都支持,实现简单,没有代码侵入
缺点
- 因为一阶段需要锁定数据库资源,等待二阶段结束才释放,所以性能较差
- 依赖关系型数据库实现事务
两段提交协议(2PC)
过程
- Prepare阶段: 协调者给每一个参与者发送Prepare消息,执行本地数据脚本但不提交事务。
- Commit/Rollback: 如果协调者收到了参与者的失败消息或者超时,直接给每个参与者发送回滚(Rollback)消息;否则,发送提交(Commit)消息;参与者根据协调者的指令执行提交或者回滚操作,释放所有事务处理过程中被占用的资源。
优点
- 简单且易于实现,而且做到了所有操作要么全部成功、要么全部失败。
缺点:
- 网络抖动导致的数据不一致: 第二阶段中协调者向参与者发送commit命令之后,一旦此时发生网络抖动,导致一部分参与者接收到了commit请求并执行,可其他未接到commit请求的参与者无法执行事务提交。进而导致整个分布式系统出现了数据不一致。
- 超时导致的同步阻塞问题: 2PC中的所有的参与者节点都为事务阻塞型,当某一个参与者节点出现通信超时,其余参与者都会被动阻塞占用资源不能释放。
- 单点故障的风险: 由于严重的依赖协调者,一旦协调者发生故障,而此时参与者还都处于锁定资源的状态,无法完成事务commit操作。虽然协调者出现故障后,会重新选举一个协调者,可无法解决因前一个协调者宕机导致的参与者处于阻塞状态的问题。
三段提交协议(3PC)
三段提交(3PC)是对两段提交(2PC)的一种升级优化,3PC在2PC的第一阶段和第二阶段中插入一个准备阶段。保证了在最后提交阶段之前,各参与者节点的状态都一致。同时在协调者和参与者中都引入超时机制,当参与者各种原因未收到协调者的commit请求后,会对本地事务进行commit,不会一直阻塞等待,解决了2PC的单点故障问题,但3PC 还是没能从根本上解决数据一致性的问题。
过程
CanCommit: 协调者向所有参与者发送CanCommit命令,询问是否可以执行事务提交操作,进行预留资源但不执行事务。如果全部响应YES则进入下一个阶段。
PreCommit: 协调者向所有参与者发送PreCommit命令,询问是否可以进行事务的预提交操作,参与者接收到PreCommit请求后,如参与者成功的执行了事务操作,则返回Yes响应,进入最终commit阶段。一旦参与者有向协调者发送了No响应,或因网络造成超时,协调者没有接到参与者的响应,协调者向所有参与者发送abort请求,参与者接受abort命令执行事务的中断。
DoCommit: 在前两个阶段中所有参与者的响应反馈均是YES后,协调者向参与者发送DoCommit命令正式提交事务,如协调者没有接收到参与者发送的ACK响应,会向所有参与者发送abort请求命令,执行事务的中断。
TCC 方案(补偿事务)
TCC模式:最终一致的分阶段事务模式,有业务侵入。一般用于支付、交易等一致性要求严格的场景。
三个阶段
过程:
- Try 阶段: 这个阶段说的是对各个服务的资源做检测以及对资源进行锁定或者预留
- Confirm 阶段: 这个阶段说的是在各个服务中执行实际的操作
- Cancel 阶段: 如果任何一个服务的业务方法执行出错,那么这里就需要进行补偿,就是执行已经执行成功的业务逻辑的回滚操作
例子:
- Try 阶段:先把两个银行账户中的资金给它冻结住就不让操作了
- Confirm 阶段:执行实际的转账操作,A 银行账户的资金扣减,B 银行账户的资金增加
- Cancel 阶段:如果任何一个银行的操作执行失败,那么就需要回滚进行补偿,就是比如 A 银行账户如果已经扣减了,但是 B 银行账户资金增加失败了,那么就得把 A 银行账户资金给加回去
优点
- Confirm阶段完成直接提交事务,释放数据库资源,性能好
- 相比AT模型,无需生成快照,无需使用全局锁,性能最强
- 不依赖数据库事务,而是依赖补偿操作,可以用于非事务型数据库
缺点
- 有代码侵入,需要人为编写try、Confirm和Cancel接口,代码量大,逻辑复杂
- 软状态,事务是最终一致
- 需要考虑Confirm和Cancel的失败情况,做好幂等处理
本地消息表
- A 系统在自己本地一个事务里操作同时,插入一条数据到消息表(状态未完成)
- 接着 A 系统将这个消息发送到 MQ 中去
- B 系统接收到消息之后,在一个事务里,往自己本地消息表里插入一条数据,同时执行其他的业务操作,如果这个消息已经被处理过了,那么此时这个事务会回滚,这样保证不会重复处理消息
- B 系统执行成功之后,就会更新自己本地消息表的状态以及调用 A 系统的接口修改消息表的状态
- 如果 B 系统处理失败了,那么就不会更新消息表状态,那么此时 A 系统会定时扫描自己的消息表,如果有没处理的消息,会再次发送到 MQ 中去,让 B 再次处理
- 这个方案保证了最终一致性,哪怕 B 事务失败了,但是 A 会不断重发消息,直到 B 那边成功为止
可靠消息最终一致性方案
直接基于 MQ 来实现事务。比如阿里的RocketMQ 就支持消息事务。
过程
- A 系统先发送一个 prepared 消息到 mq,如果这个 prepared 消息发送失败那么就直接取消操作别执行了
- 如果这个消息发送成功过了,那么接着执行本地事务,如果成功就告诉 mq 发送确认消息,如果失败就告诉 mq 回滚消息
- 如果发送了确认消息,那么此时 B 系统会接收到确认消息,然后执行本地的事务
- mq 会自动定时轮询所有 prepared 消息回调你的接口,问你,这个消息是不是本地事务处理失败了,所有没发送确认消息?那是继续重试还是回滚?一般来说这里你就可以查下数据库看之前本地事务是否执行,如果回滚了,那么这里也回滚吧。这个就是避免可能本地事务执行成功了,别确认消息发送失败了。
- 这个方案里,要是系统 B 的事务失败了咋办?重试,自动不断重试直到成功,如果实在是不行,要么就是针对重要的资金类业务进行回滚,比如 B 系统本地回滚后,想办法通知系统 A 也回滚;或者是发送报警由人工来手工回滚和补偿
最大努力通知方案
- 系统 A 本地事务执行完之后,发送个消息到 MQ
- 这里会有个专门消费 MQ 的最大努力通知服务,这个服务会消费 MQ 然后写入数据库中记录下来,或者是放入个内存队列也可以,接着调用系统 B 的接口
- 要是系统 B 执行成功就 ok 了;要是系统 B 执行失败了,那么最大努力通知服务就定时尝试重新调用系统 B,反复 N 次,最后还是不行就放弃或者上报。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
2020-12-21 md5算法 C++ 实现