Spring Cloud异步场景分布式事务怎样做?试试RocketMQ

本文深入探讨RocketMQ事务消息机制,解析其如何确保本地事务与消息发送的原子性,通过半消息、事务提交与回查流程,实现微服务架构下的数据一致性。同时,介绍了SpringCloud中事务消息的实现步骤与应用场景。

file

一、背景

在微服务架构中,我们常常使用异步化的手段来提升系统的 吞吐量解耦 上下游,而构建异步架构最常用的手段就是使用 消息队列(MQ),那异步架构怎样才能实现数据一致性呢?本文主要介绍如何使用RocketMQ事务消息来解决一致性问题。

RocketMQ 是阿里巴巴开源的分布式消息中间件,目前已成为 Apache 的顶级项目。历经多次天猫双十一海量消息考验,具有高性能、低延时和高可靠等特性

PS:同步场景怎样保证一致性?请看文章《Spring Cloud同步场景分布式事务怎样做?试试Seata

 

二、MQ选型

可以看到在 业务处理 方面来说 RocketMQ 优于其他对手,而且原生支持 事务消息
mark
PS:业务系统用的是其他 MQ 产品但是又需要 事务消息 怎么办?学习原理自己开发实现!

 

三、什么是事务消息

例如下图的场景:生成订单记录 -> MQ -> 增加积分
mark
我们是应该先 创建订单记录,还是先 发送MQ消息 呢?

  1. 先发送MQ消息:这个明显是不行的,因为如果消息发送成功,而订单创建失败的话是没办法把消息收回来的

  2. 先创建订单记录:如果订单创建成功后MQ消息发送失败 抛出异常,因为两个操作都在本地事务中所以订单数据是可以 回滚

上面的 方式二 看似没问题,但是 网络是不可靠的!如果 MQ 的响应因为网络原因没有收到,所以在面对不确定的结果只好进行回滚;但是 MQ 端又确实是收到了这条消息的,只是回给客户端的 响应丢失 了!
 
所以 事务消息 就是用来保证 本地事务MQ消息发送 的原子性!

 

四、RocketMQ事务消息原理

mark
主要的逻辑分为两个流程:

  • 事务消息发送及提交
    1. 发送 half消息
    2. MQ服务端 响应消息写入结果
    3. 根据发送结果执行 本地事务(如果写入失败,此时half消息对业务 不可见,本地逻辑不执行)
    4. 根据本地事务状态执行 Commit 或者 Rollback(Commit操作生成消息索引,消息对消费者 可见
       
  • 回查流程
    1. 对于长时间没有 Commit/Rollback 的事务消息(pending 状态的消息),从服务端发起一次 回查
    2. Producer 收到回查消息,检查回查消息对应的 本地事务状态
    3. 根据本地事务状态,重新 Commit 或者 Rollback

 
逻辑时序图
mark
 

五、异步架构一致性实现思路

从上面的原理可以发现 事务消息 仅仅只是保证本地事务和MQ消息发送形成整体的 原子性,而投递到MQ服务器后,并无法保证消费者一定能消费成功!
 
如果 消费端消费失败 后的处理方式,建议是记录异常信息然后 人工处理,并不建议回滚上游服务的数据(因为两者是 解耦 的,而且 复杂度 太高)
 
我们可以利用 MQ 的两个特性 重试死信队列 来协助消费端处理:

  1. 消费失败后进行一定次数的 重试
  2. 重试后也失败的话该消息丢进 死信队列
  3. 另外起一个线程监听消费 死信队列 里的消息,记录日志并且预警!

因为有 重试 所以消费者需要实现 幂等性

 

六、分布式事务场景样例

下面就用刚刚提到的场景:生成订单记录 -> MQ -> 增加积分;来简单讲一下 Spring Cloud 中应该怎么做,详细代码请 下载demo 查看。
PS:怎样安装部署RocketMQ可以参考《Apache RocketMQ 消息队列部署与可视化界面安装

6.1. 引入依赖

使用 spring-cloud-stream 框架来访问 RocketMQ
mark

Spring Cloud Stream 是一个构建消息驱动的框架,通过抽象的定义实现应用与MQ消息队列之间的解耦,目前支持 RabbitMQkafkaRocketMQ
mark

 

6.2. 开启事务消息

消息生产者需要添加 transactional: true 开启 事务消息
mark
 

6.3. 订单服务发送half消息

mark

因为开启了 事务消息 所以这里发送的是 half消息 对于消费端是 不可见

 

6.4. 订单服务监听half消息

使用 @RocketMQTransactionListener 注解监听 半消息,并实现 RocketMQLocalTransactionListener 接口,该接口有两个方法

  • executeLocalTransaction:用于提交本地事务
  • checkLocalTransaction:用于事务回查

mark

如果提交事务消息失败,需等待约1分钟左右 事务回查 方法才会被调用

 

6.5. 积分服务消费消息

mark

注意:因为有 重试 这里如果是真实的业务需要自行实现 幂等性

 

6.6. 消费死信队列预警mark

监听并消费死信队列中的消息,用于记录错误日志,并且预警通知 运维人员

 

6.7. 测试用例

demo中提供了3个接口分别测试不同的场景:

  • 事务成功
    http://localhost:11002/success
    流程如下:

    1. 订单创建 成功
    2. 提交事务消息 成功
    3. 消费消息增加积分 成功
  • 订单创建成功但提交事务消息失败
    http://localhost:11002/produceError
    流程如下:

    1. 订单创建 成功
    2. 提交事务消息 失败
    3. 事务回查(等待1分钟左右) 成功
    4. 提交事务消息 成功
    5. 消费消息增加积分 成功
  • 消费消息失败
    http://localhost:11002/consumeError
    流程如下:

    1. 订单创建 成功
    2. 提交事务消息 成功
    3. 消费消息增加积分 失败
    4. 重试消费消息 失败
    5. 进入死信队列 成功
    6. 消费死信队列的消息 成功
    7. 记录日志并发出预警 成功

 

七、demo下载地址

https://gitee.com/zlt2000/microservices-platform/tree/master/zlt-demo/rocketmq-demo/rocketmq-transactional

 
推荐阅读

 
扫码关注有惊喜!
file

<think>好的,用户想了解Spring Cloud中实现分布式事务的方法和最佳实践。首先,我需要回忆一下相关知识。分布式事务在微服务架构中确实是个大问题,因为每个服务都有自己的数据库,传统的事务管理方式不管用了。我记得Spring Cloud有几种常见的解决方案,比如Seata、Saga模式、TCC,还有事务消息,比如用RocketMQ实现的。 接下来,用户的问题可能想知道这些方法具体怎么用,各自的优缺点,以及最佳实践是什么。首先,我应该分点列出主要的实现方式,然后逐一解释每种方法的原理、适用场景以及优缺点。比如,Seata是基于两阶段提交的,而Saga是长事务解决方案,通过补偿机制。事务消息则依赖消息队列来确保最终一致性。 然后,最佳实践部分需要结合实际开发中的经验,比如选择合适的事务模型、结合业务场景、配置重试和幂等性,以及监控和日志的重要性。可能还需要提到Spring Cloud和这些框架的集成方式,比如如何使用Seata的starter,或者如何配置RocketMQ事务消息。 需要注意引用提供的参考文献,比如引用[1]提到Seata、Saga和TCC,引用[2]和[3]讨论了事务消息和补偿机制可能的问题。引用[4]中的架构演进可能和分布式事务的应用场景有关联,但可能不需要直接引用。 另外,用户可能还想知道在哪种情况下选择哪种方法,比如高一致性要求的用TCC,而最终一致性的可以用Saga或事务消息。还要注意可能遇到的陷阱,比如补偿机制失败的情况,如引用[3]提到的,这时候需要有重试和监控机制。 最后,生成的相关问题需要围绕实现方式、比较、补偿机制处理、事务消息集成等,确保覆盖用户可能进一步询问的方向。检查是否所有信息都准确,特别是技术细节和框架版本是否最新,比如Seata的版本是否有变化,但用户提供的引用中没有具体版本,可能不需要深入。 总结,结构应该是先介绍分布式事务的挑战,然后分点讲解方法,接着最佳实践,最后相关问题和引用标注。确保语言简洁,技术点明确,帮助用户清晰理解。</think>### Spring Cloud分布式事务的实现方式与最佳实践 在微服务架构中,分布式事务的挑战主要源于服务间的数据隔离和网络通信不确定性。Spring Cloud 提供了多种解决方案,以下是核心实现方式及其最佳实践: --- #### 一、主要实现方式 1. **Seata(AT 模式)** - **原理**:基于两阶段提交(2PC),通过全局事务协调器(TC)管理分支事务的提交与回滚。 - **适用场景**:高一致性要求的业务(如支付、订单)。 - **代码示例**: ```java @GlobalTransactional public void createOrder() { // 调用多个微服务的事务操作 } ``` - **优点**:对业务代码侵入低,支持自动补偿。 - **缺点**:依赖独立的事务协调器,性能开销较高[^1]。 2. **Saga 模式** - **原理**:将事务拆分为多个本地事务,通过补偿操作(正向/逆向)实现最终一致性。 - **适用场景**:长事务(如物流、库存)。 - **实现方式**: - 编排式(Orchestration):由中心协调器控制流程(如使用 Camunda)。 - 协同式(Choreography):通过事件驱动(如 Spring Cloud Stream)。 - **优点**:无锁设计,适合高并发场景。 - **缺点**:补偿逻辑需手动实现,复杂度高[^3]。 3. **TCC(Try-Confirm-Cancel)** - **原理**:通过预留资源(Try)、提交(Confirm)、回滚(Cancel)三阶段保证一致性。 - **适用场景**:对一致性要求极高且资源可预留的业务(如账户余额冻结)。 - **代码示例**: ```java @TwoPhaseBusinessAction(name = "deductBalance", commitMethod = "confirm", rollbackMethod = "cancel") public boolean tryDeductBalance(BusinessActionContext context) { // 预留资源 } ``` - **优点**:强一致性,无全局锁。 - **缺点**:业务侵入性强,需实现三阶段接口。 4. **事务消息(如 RocketMQ)** - **原理**:通过消息队列实现最终一致性,生产者发送事务消息,消费者监听并处理。 - **适用场景**:异步解耦场景(如通知、日志)。 - **实现步骤**: 1. 生产者发送半消息到 MQ。 2. 执行本地事务并提交。 3. MQ 投递消息,消费者处理。 - **优点**:异步高效,适合高吞吐场景。 - **缺点**:需处理消息重复消费(需幂等设计)[^2]。 --- #### 二、最佳实践 1. **按业务需求选择模型** - **强一致性**:优先选择 Seata 或 TCC。 - **最终一致性**:使用 Saga 或事务消息。 2. **配置重试与幂等性** - **重试机制**:结合 Spring Retry 或 Resilience4j 实现超时重试。 - **幂等设计**:通过唯一事务 ID 或数据库乐观锁避免重复操作。 3. **监控与日志追踪** - 集成 Sleuth + Zipkin 追踪事务链路。 - 使用 Prometheus + Grafana 监控事务成功率与延迟。 4. **框架集成示例** - **Seata 集成**: ```yaml spring: cloud: alibaba: seata: tx-service-group: my_tx_group ``` - **RocketMQ 事务消息**: ```java @Bean public TransactionListener customTransactionListener() { return new CustomTransactionListenerImpl(); } ``` --- #### 三、常见问题与规避 - **补偿失败**:通过异步重试队列 + 人工干预兜底。 - **网络分区**:设置合理超时时间,避免事务悬挂。 - **性能瓶颈**:Seata 模式下可通过分库分表减少锁竞争。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值