分布式事务Seata【四】事务消息

简介: 本篇介绍本地消息表和MQ事务方案

本地消息表

方案简介

本地消息表的方案最初是由 eBay 提出,核心思路是将分布式事务拆分成本地事务进行处理。

方案通过在事务主动发起方额外新建事务消息表,事务发起方处理业务和记录事务消息在本地事务中完成,轮询事务消息表的数据发送事务消息,事务被动方基于消息中间件消费事务消息表中的事务。

这样设计可以避免”业务处理成功 + 事务消息发送失败",或"业务处理失败 + 事务消息发送成功"的棘手情况出现,保证 2 个系统事务的数据一致性。

处理流程

下面把分布式事务最先开始处理的事务方称为事务主动方,在事务主动方之后处理的业务内的其他事务称为事务被动方。

为了方便理解,下面继续以电商下单为例进行方案解析,这里把整个过程简单分为扣减库存,订单创建 2 个步骤。

库存服务和订单服务分别在不同的服务器节点上,其中库存服务是事务主动方,订单服务是事务被动方。

事务的主动方需要额外新建事务消息表,用于记录分布式事务的消息的发生、处理状态。

整个业务处理流程如下:

image.png

步骤1:事务主动方处理本地事务。

事务主动方在本地事务中处理业务更新操作和写消息表操作。上面例子中库存服务阶段在本地事务中完成扣减库存和写消息表(图中 1、2)。

步骤 2:事务主动方通过消息中间件,通知事务被动方处理事务通知事务待消息。

消息中间件可以基于 Kafka、RocketMQ 消息队列,事务主动方主动写消息到消息队列,事务消费方消费并处理消息队列中的消息。

上面例子中,库存服务把事务待处理消息写到消息中间件,订单服务消费消息中间件的消息,完成新增订单(图中 3 - 5)。

步骤 3:事务被动方通过消息中间件,通知事务主动方事务已处理的消息。

上面例子中,订单服务把事务已处理消息写到消息中间件,库存服务消费中间件的消息,并将事务消息的状态更新为已完成(图中 6 - 8)。

为了数据的一致性,当处理错误需要重试,事务发送方和事务接收方相关业务处理需要支持幂等。

具体保存一致性的容错处理如下:

  • 当步骤 1 处理出错,事务回滚,相当于什么都没发生。
  • 当步骤 2、步骤 3 处理出错,由于未处理的事务消息还是保存在事务发送方,事务发送方可以定时轮询为超时消息数据,再次发送到消息中间件进行处理。事务被动方消费事务消息重试处理。
  • 如果是业务上的失败,事务被动方可以发消息给事务主动方进行回滚。
  • 如果多个事务被动方已经消费消息,事务主动方需要回滚事务时需要通知事务被动方回滚。

方案总结

方案的优点如下:

  • 从应用设计开发的角度实现了消息数据的可靠性,消息数据的可靠性不依赖于消息中间件,弱化了对 MQ 中间件特性的依赖。
  • 方案轻量,容易实现。

缺点如下:

  • 与具体的业务场景绑定,耦合性强,不可公用。
  • 消息数据与业务数据同库,占用业务系统资源。
  • 业务系统在使用关系型数据库的情况下,消息服务性能会受到关系型数据库并发性能的局限。

MQ 事务方案

方案简介

基于 MQ 的分布式事务方案其实是对本地消息表的封装,将本地消息表基于 MQ 内部,其他方面的协议基本与本地消息表一致。

处理流程

下面主要基于 RocketMQ 4.3 之后的版本介绍 MQ 的分布式事务方案。

在本地消息表方案中,保证事务主动方发写业务表数据和写消息表数据的一致性是基于数据库事务,RocketMQ 的事务消息相对于普通 MQ,相对于提供了 2PC 的提交接口,方案如下:

正常情况:事务主动方发消息

image.png

这种情况下,事务主动方服务正常,没有发生故障,发消息流程如下:

  • 图中 1:发送方向 MQ 服务端(MQ Server)发送 half 消息。
  • 图中 2:MQ Server 将消息持久化成功之后,向发送方 ack 确认消息已经发送成功。
  • 图中 3:发送方开始执行本地事务逻辑。
  • 图中 4:发送方根据本地事务执行结果向 MQ Server 提交二次确认(commit 或是 rollback)。
  • 图中 5:MQ Server 收到 commit 状态则将半消息标记为可投递,订阅方最终将收到该消息;MQ Server 收到 rollback 状态则删除半消息,订阅方将不会接受该消息。

异常情况:事务主动方消息恢复

image.png

在断网或者应用重启等异常情况下,图中 4 提交的二次确认超时未到达 MQ Server,此时处理逻辑如下:

  • 图中 5:MQ Server 对该消息发起消息回查。
  • 图中 6:发送方收到消息回查后,需要检查对应消息的本地事务执行的最终结果。
  • 图中 7:发送方根据检查得到的本地事务的最终状态再次提交二次确认。
  • 图中 8:MQ Server基于 commit/rollback 对消息进行投递或者删除。

介绍完 RocketMQ 的事务消息方案后,由于前面已经介绍过本地消息表方案,这里就简单介绍 RocketMQ 分布式事务:

image.png

事务主动方基于 MQ 通信通知事务被动方处理事务,事务被动方基于 MQ 返回处理结果。

如果事务被动方消费消息异常,需要不断重试,业务处理逻辑需要保证幂等。

如果是事务被动方业务上的处理失败,可以通过 MQ 通知事务主动方进行补偿或者事务回滚。

总结

相比本地消息表方案,MQ 事务方案优点是:

  • 消息数据独立存储 ,降低业务系统与消息系统之间的耦合。
  • 吞吐量由于使用本地消息表方案。

缺点是:

  • 一次消息发送需要两次网络请求(half 消息 + commit/rollback 消息) 。
  • 业务处理服务需要实现消息状态回查接口。
相关实践学习
消息队列RocketMQ版:基础消息收发功能体验
本实验场景介绍消息队列RocketMQ版的基础消息收发功能,涵盖实例创建、Topic、Group资源创建以及消息收发体验等基础功能模块。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
目录
相关文章
|
10天前
|
关系型数据库 MySQL 数据库
SpringCloud2023中使用Seata解决分布式事务
对于分布式系统而言,需要保证分布式系统中的数据一致性,保证数据在子系统中始终保持一致,避免业务出现问题。分布式系统中对数据的操作要么一起成功,要么一起失败,必须是一个整体性的事务。Seata简化了这个使用过程。
17 2
|
19天前
|
Java 关系型数据库 MySQL
(二十七)舞动手指速写一个Seata-XA框架解决棘手的分布式事务问题
相信大家对于事务问题都不陌生,在之前《MySQL事务篇》中曾详解过MySQL的事务机制,在传统的单库环境下开发,咱们可依赖于MySQL所提供的事务机制,来确保单个事务内的一组操作,要么全部执行成功,要么全部执行失败。
|
4天前
|
Java Nacos Docker
"揭秘!Docker部署Seata遇上Nacos,注册成功却报错?这些坑你不得不防!一网打尽解决秘籍,让你的分布式事务稳如老狗!"
【8月更文挑战第15天】在微服务架构中,Nacos搭配Seata确保数据一致性时,Docker部署Seata后可能出现客户端连接错误,如“can not connect to services-server”。此问题多由网络配置不当、配置文件错误或版本不兼容引起。解决策略包括:调整Docker网络设置确保可达性;检查并修正`file.conf`和`registry.conf`中的Nacos地址和端口;验证Seata与Nacos版本兼容性;修改配置后重启服务;参考官方文档和最佳实践进行配置。通过这些步骤,能有效排除故障,保障服务稳定运行。
13 0
|
1月前
|
SQL 关系型数据库 MySQL
乐观锁在分布式数据库中与事务隔离级别结合使用
乐观锁在分布式数据库中与事务隔离级别结合使用
|
2月前
|
Java 数据库 开发者
深入解析 Spring Cloud Seata:分布式事务的全面指南
深入解析 Spring Cloud Seata:分布式事务的全面指南
131 1
|
2月前
|
存储 关系型数据库 Java
技术经验解读:三种分布式事务LCN、Seata、MQ
技术经验解读:三种分布式事务LCN、Seata、MQ
56 0
|
2月前
|
消息中间件 SQL 关系型数据库
分布式事务-seata
分布式事务-seata
60 0
|
26天前
|
存储 缓存 NoSQL
Redis常见面试题(二):redis分布式锁、redisson、主从一致性、Redlock红锁;Redis集群、主从复制,哨兵模式,分片集群;Redis为什么这么快,I/O多路复用模型
redis分布式锁、redisson、可重入、主从一致性、WatchDog、Redlock红锁、zookeeper;Redis集群、主从复制,全量同步、增量同步;哨兵,分片集群,Redis为什么这么快,I/O多路复用模型——用户空间和内核空间、阻塞IO、非阻塞IO、IO多路复用,Redis网络模型
Redis常见面试题(二):redis分布式锁、redisson、主从一致性、Redlock红锁;Redis集群、主从复制,哨兵模式,分片集群;Redis为什么这么快,I/O多路复用模型
|
30天前
|
NoSQL Java Redis
分布式锁实现原理问题之使用Redis的setNx命令来实现分布式锁问题如何解决
分布式锁实现原理问题之使用Redis的setNx命令来实现分布式锁问题如何解决
|
1天前
|
缓存 NoSQL Java
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解、如何添加锁解决缓存击穿问题?分布式情况下如何添加分布式锁
这篇文章介绍了如何在SpringBoot项目中整合Redis,并探讨了缓存穿透、缓存雪崩和缓存击穿的问题以及解决方法。文章还提供了解决缓存击穿问题的加锁示例代码,包括存在问题和问题解决后的版本,并指出了本地锁在分布式情况下的局限性,引出了分布式锁的概念。
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解、如何添加锁解决缓存击穿问题?分布式情况下如何添加分布式锁