分布式事务(二)消息事务方案

前言

我们在上一篇文章中大致介绍了常见的分布式事务方案。基于消息的分布式事务虽然有很多的缺点,但是在合适的场景中还是可以使用的。该方案最大的优点可能就是不需要框架,只需要一个实现了反查事务消息的MQ就可以实现,简单粗暴。对于资源无法锁定导致后续不好回滚的问题,也可以在业务层通过“预扣除”、“加锁”等方式,实现资源锁定。

方案回顾

在这里插入图片描述

  1. 步骤1-2是在本地事务执行之前,服务A负责生成一个全局唯一的事务ID,并在消息管理服务上注册一个消息。这一步如果失败,整个事务被判定失败,不会出现数据不一致问题。这两个步骤主要是为了容错,后续当步骤4如果没有执行,消息管理服务会定时捞出未提交的事务,反查服务A的接口,确认事务是提交还是取消。提交则继续往下传递,取消则判定当前事务失败。
  2. 步骤3是执行本地事务。这一步如果失败,事务判定失败,继续调用步骤4取消事务。
  3. 步骤4是提交/取消事务,告诉消息管理服务,消息是否可以继续往下传播。这一步如果失败,会有步骤1中所说的反查的操作进行补偿。
  4. 步骤5是消息继续往下一个节点传递。如果消息没有被ACK,会定时重发。因此下游节点需要实现幂等。
  5. 步骤6是服务B执行本地事务。
  6. 步骤7用于确认服务B的事务也执行完毕。如果没有执行,步骤5会重发直到得到反馈。如果步骤6一直没有成功,在多次重试后需要人工介入。

反查操作的实现

整个方案的流程基本都是基于二次确认和消息的重试来完成,比较好理解,唯独”反查“这一步需要说明一下。

很多MQ的Client SDK中都提供了一个反查接口,用户只需要实现这个接口即可。

但是如果每个接入分布式事务的方法都需要实现一个接口,让消息管理服务来反查步骤3的本地事务是否成功,那工作量是不可接受的。

我们首先介绍一种在业务层实现的方式,先看一下常见的Spring框架下事务的执行方式:

Spring中开启、提交事务,都是通过Spring的@Transactional注解实现的。此时,我们可以实现一个Clent SDK,包含了我们自定义的事务注解,如:@MessageTransaction,并在业务数据库中建立一张专门用于记录消息事务的表。

@MessageTransaction注解,主要是为了让Clent SDK中的自定义AOP切面可以通过扫描该注解,确定要执行事务的方法,并确保与业务方法在同一个Spring事务中。

当业务在处理本地事务时,我们的自定义AOP会隐式往消息事务的表中插入一条数据。注意要通过@Order调整AOP顺序,确保Clent SDK的AOP插入操作和业务在同一个Spring事务里。由于往事务表中插入数据的操作是自定义注解AOP隐式实现的,因此对开发者无感。

Clent SDK的插入数据操作与业务操作在同一个本地事务中,因此可以同时成功或同时失败。插入表中的数据包含有唯一的事务ID,后续消息管理服务反查Client时,只要看数据库中是否还有这个事务ID就知道本地事务是否成功。由于往事务表中插入数据的操作是自定义注解通过AOP隐式实现的,因此对开发者无感。

至于反查的通信方式,可以通过TCP长连接通信,或者Client SDK自带http服务端口等方式。

另外一种方式,我们可以在数据源层实现隐式数据插入操作,但这就需要我们对sql的解析等操作,这在一些分布式事务框架中已经实现。当然,实现方式有很多,本文只是列出其中一种比较简单的思路。

总结

这次我们介绍了基于消息的事务方案,在后面的文章中,我们会继续介绍其他分布式事务框架的具体方案。

欢迎专注我的公众号

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值