分布式事务

分布式事务

两阶段提交(XA)

两阶段提交需要一个事务管理器,来协调两个阶段。

  1. 事务管理器会在每个数据库进行预提交,检查是否预提交都就绪
  2. 如果都就绪,则让每个数据库提交事务,否则回滚事务
  • 尽量保证了数据的一致性
  • 事务管理器有单例问题,宕机了整个系统不可用
  • 在第二步里通知提交或者回滚都可能通知失败,导致数据不一致
  • 在第二步里通知到一半,事务管理器宕机选举,新主节点不知道那些服务还没通知
  • 依赖于数据库,性能低
  • 不符合微服务设计的每个微服务只能处理自己的数据库

TCC(Try Confirm Cancel)

  1. Try:对各个服务的资源进行检查和冻结
  2. Confirm:将冻结转为执行具体的操作
  3. Cancel:在确认阶段失败了,执行已成功的操作的补偿操作
  • 回滚依赖于自己实现的补偿代码
  • 适合于钱等需要较强一致性的场景
  • 需要分布式事务整个流程较短

Saga

saga的流程是依次执行提交各个服务的本地事务,如无意外都执行成功则分布式事务完成。
如果其中有一个事务失败,则对已经执行成功的事务进行补偿操作。

  • 适合于分布式事务流程比较长
  • 一致性比TCC差
  • 不保证事务的隔离性

TCC与Saga

  • 在TCC的第一步中,全部本地事务都是还没提交的。而Saga里依次执行本地事务是执行就提交的
  • TCC还需要先进行try操作进行冻结。而Saga是直接执行提交,所以少了一次调用
  • 因为TCC需要等待全部本地事务进行冻结,所以在这个阶段资源会都被阻塞,需要较短的分布式事务。
    而Saga提交的颗粒度是本地事务,所以适合于较长的分布式事务
  • 因为TCC是在一步里确认全部的本地事务,所以一致性强于Saga的逐个本地事务进行提交
  • 因为TCC在try里阻塞了资源,所以分布式事务之间是隔离的。而Saga的逐个本地事务则不隔离

本地消息表

  1. A服务在本地事务里除了进行业务操作,还在一个消息表里插入一条数据,然后往MQ里丢一条消息
  2. A服务也会定期扫描消息表,把消息表的消息丢到MQ里
  3. B服务从MQ收到消息后执行本地事务。如果成功则去除A服务里消息表对应的数据,否则通知A服务执行补偿操作
  • 依赖于数据库管理事务,性能低

最大努力通知

适合于不支持消息事务的MQ。

  1. A服务执行本地事务,执行成功后往MQ里丢一条消息
  2. 有一个最大努力通知服务来专门消费MQ的消息,去调B服务来执行本地事务
  3. 如果B服务执行成功,则分布式事务完成,否则重试几次,重试不行就放弃

可靠消息服务

需要使用一个MQ来实现,其功能目前只有RocketMQ支持消息事务。

  1. A服务向MQ丢一条消息,MQ只先持久化消息,不放到队列里。如果失败了则取消事务
  2. 丢成功以后,A服务执行本地事务。如果执行成功通知MQ把消息放到队列里,否则丢弃消息取消事务
  3. 其中A服务对MQ的调用如果丢失了,MQ会在消息投递后的一段时间后,回调A服务的接口,查询A服务的本地事务是执行已提交、已回滚还是执行中
  4. 之后B服务就会从MQ里收到消息,然后同步执行本地事务。成功的话向MQ提交,分布式事务完成,否则B服务会有个重试次数,再不行则报警
  • A服务的本地事务与MQ同步是异步的,以提高A服务的并发
  • A服务与MQ的异步消息丢失通过MQ回调来弥补

参考文章:

常用的分布式事务解决方案

分布式事务,这一篇就够了

分布式事务了解吗?


分布式事务
https://cellargalaxy.github.io/posts/分布式/4.分布式事务/
作者
cellargalaxy
发布于
2020年7月9日
许可协议