分布式事务解决方案

590 阅读4分钟

「这是我参与11月更文挑战的第22天,活动详情查看:2021最后一次更文挑战」。

概念

在分布式系统中,如果使用到事务就会涉及到分布式事务,例如订购业务,订购分为下单和减库存,

下单和减库存是两个独立的服务,如果下单成功,但是减库存失败,就会造成超卖的情况,这时候就要通过分布式事务来解决这种场景。

分布式事务解决方案

XA方案

XA方案也叫做两阶段提交事务方案,例如公司团建,会有个主席来负责组织团建。

第一个阶段,一般主席会提前一周问一下团队里的每个人,问他们去不去,这个时候主席会等待每个人的回答,如果所有人都ok,那么就可以决定一起去,如果任何一个人回答说不去,那么主席就会取消这次活动。

第二阶段就是大家一起去团建。

两阶段提交,有个事务管理器的概念,负责协调多个数据库(资源管理器)的事务,事务管理器会问各个数据库是否准备好,如果每个数据库都ok,就正式提交事务,在各个数据库上执行操作,如果存在数据库回答不ok,就会全部回滚事务。

这种分布式事务方案,比较适合单块应用里跨多个库的分布式事务,但这种方案严重依赖于数据库层面来搞定复杂的事务,所以不适合高并发场景。

TCC方案

TCC 全称是 Try、Confirm、Cancel

这个其实是用到了补偿的概念,分为了三个阶段:

  • Try阶段:这个阶段说的是各个服务的资源做检测以及对资源进行锁定或者预留。

  • Confirm阶段: 这个阶段说的是在各个服务中执行的实际的操作。

  • Cancel阶段:如果任何一个服务的业务方法执行出错,那么这里就需要进行补偿,就是执行已经执行成功的业务逻辑的回滚操作。

例如跨银行转账的时候,要涉及到两个银行的分布式事务,如果用TCC方案来实现,思路是这样的 :

  • try阶段:先把两个银行账户的资金给它冻结住不让操作。

  • confirm阶段:执行实际的转账操作,A银行账户资金扣减,B银行账户的资金增加

  • Cancel阶段: 如果任何一个银行的操作执行失败,那么就需要回滚进行补偿,例如A银行扣减成功,B银行资金增加失败,那就就需要A银行账户资金给加回去。

这种方案也几乎很少人使用,因为这个事务回滚实际上是严重依赖于你自己写代码来回滚和补偿,会造成补偿代码巨大。

这种方案适合一致性要求很高,属于系统中核心之核心的场景,例如常见的资金类场景,就可以用TCC方案。

可靠消息最终一致性方案

基于MQ来实现事务,例如阿里的RocketMQ支持消息事务。

  1. A系统先发送一个prepared消息到mq,如果这个prepared消息发送失败那么就直接取消操作别执行。

  2. 如果消息发送成功,就接着执行本地事务,如果成功就告诉mq发送确认消息,如果失败就告诉mq回滚消息。

  3. 如果发送了确认消息,此时b系统会接收到确认消息,然后执行本地的事务。

  4. mq会自动定时轮询所有prepared消息回调你的接口,询问消息是不是本地事务处理失败,所以没发送确认消息,那是继续重试还是回滚,一般来说这里可以查下数据库看之前本地事务是否执行,如果回滚,这里也会回滚,避免了可能本地事务执行成功,确认消息发送失败了。

  5. 要是系统B的事务失败了,就会进行重试,自动不断重试直到成功。如果实在不行,要么就针对重要的资金类进行回滚,例如B系统本地回滚,想办法通知A也回滚,,或者发送报警来手工回滚和补偿。