你再不知道分布式事务,我就真的生气了( 三 )


  • 主业务服务:主业务服务负责发起并完成整个业务活动 。
  • 从业务服务:从业务服务是整个业务活动的参与方,实现 Try、Confirm、Cancel 操作,供主业务服务调用 。
  • 业务活动管理器:业务活动管理器管理控制整个业务活动,包括记录事务状态,调用从业务服务的 Confirm 操作,调用从业务服务的 Cancel 操作等 。
下面再拿用户下单购买礼物作为例子来模拟 TCC 实现分布式事务的过程:假设用户 A 余额为 100 金币,拥有的礼物为 5 朵 。A 花了 10 个金币,下订单,购买 10 朵玫瑰 。余额、订单、礼物都在不同数据库 。
TCC 的 Try 阶段:
  • 生成一条订单记录,订单状态为待确认 。
  • 将用户 A 的账户金币中余额更新为 90,冻结金币为 10(预留业务资源) 。
  • 将用户的礼物数量为 5,预增加数量为 10 。
  • Try 成功之后,便进入 Confirm 阶段 。
  • Try 过程发生任何异常,均进入 Cancel 阶段 。

你再不知道分布式事务,我就真的生气了

文章插图
 
TCC 的 Confirm 阶段:
  • 订单状态更新为已支付 。
  • 更新用户余额为 90,可冻结为 0 。
  • 用户礼物数量更新为 15,预增加为 0 。
  • Confirm 过程发生任何异常,均进入 Cancel 阶段 。
  • Confirm 过程执行成功,则该事务结束 。

你再不知道分布式事务,我就真的生气了

文章插图
 
TCC 的 Cancel 阶段:
  • 修改订单状态为已取消 。
  • 更新用户余额回 100 。
  • 更新用户礼物数量为 5 。
 
你再不知道分布式事务,我就真的生气了

文章插图
 
TCC 方案让应用可以自定义数据库操作的粒度,降低了锁冲突,可以提升性能 。
但是也有以下缺点:
  • 应用侵入性强,Try、Confirm、Cancel 三个阶段都需要业务逻辑实现 。
  • 需要根据网络、系统故障等不同失败原因实现不同的回滚策略,实现难度大,一般借助 TCC 开源框架,ByteTCC,TCC-transaction,Himly 。
本地消息表
eBay 最初提出本地消息表这个方案,来解决分布式事务问题 。业界目前使用这种方案是比较多的,它的核心思想就是将分布式事务拆分成本地事务进行处理 。
可以看一下基本的实现流程图:
你再不知道分布式事务,我就真的生气了

文章插图
 
基本实现思路如下 。
发送消息方:
  • 需要有一个消息表,记录着消息状态相关信息 。
  • 业务数据和消息表在同一个数据库,即要保证它俩在同一个本地事务 。
  • 在本地事务中处理完业务数据和写消息表操作后,通过写消息到 MQ 消息队列 。
  • 消息会发到消息消费方,如果发送失败,即进行重试 。
消息消费方:
  • 处理消息队列中的消息,完成自己的业务逻辑 。
  • 此时如果本地事务处理成功,则表明已经处理成功了 。
  • 如果本地事务处理失败,那么就会重试执行 。
  • 如果是业务上面的失败,给消息生产方发送一个业务补偿消息,通知进行回滚等操作 。
生产方和消费方定时扫描本地消息表,把还没处理完成的消息或者失败的消息再发送一遍 。如果有靠谱的自动对账补账逻辑,这种方案还是非常实用的 。
优缺点:该方案的优点是很好地解决了分布式事务问题,实现了最终一致性 。缺点是消息表会耦合到业务系统中 。
最大努力通知
什么是最大通知?最大努力通知也是一种分布式事务解决方案 。
你再不知道分布式事务,我就真的生气了

文章插图
 
下面是企业网银转账一个例子:
  • 企业网银系统调用前置接口,跳转到转账页 。
  • 企业网银调用转账系统接口 。
  • 转账系统完成转账处理,向企业网银系统发起转账结果通知,若通知失败,则转账系统按策略进行重复通知 。
  • 企业网银系统未接收到通知,会主动调用转账系统的接口查询转账结果 。
  • 转账系统会遇到退汇等情况,会定时回来对账 。
最大努力通知方案的目标,就是发起通知方通过一定的机制,最大努力将业务处理结果通知到接收方 。
最大努力通知实现机制如下:
你再不知道分布式事务,我就真的生气了

文章插图
 
最大努力通知解决方案:要实现最大努力通知,可以采用 MQ 的 ACK 机制 。


推荐阅读