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

 

一、背景

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

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

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

 

二、MQ选型

可以看到在 业务处理 方面来说 RocketMQ 优于其他对手,而且原生支持 事务消息

PS:业务系统用的是其他 MQ 产品但是又需要 事务消息 怎么办?学习原理自己开发实现!

 

三、什么是事务消息

例如下图的场景:生成订单记录 -> MQ -> 增加积分

我们是应该先 创建订单记录,还是先 发送MQ消息 呢?

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

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

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

 

四、RocketMQ事务消息原理

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

  • 事务消息发送及提交

    1. 发送 half消息

    2. MQ服务端 响应消息写入结果

    3. 根据发送结果执行 本地事务(如果写入失败,此时half消息对业务 不可见,本地逻辑不执行)

    4. 根据本地事务状态执行 Commit 或者 Rollback(Commit操作生成消息索引,消息对消费者 可见
       

  • 回查流程

    1. 对于长时间没有 Commit/Rollback 的事务消息(pending 状态的消息),从服务端发起一次 回查

    2. Producer 收到回查消息,检查回查消息对应的 本地事务状态

    3. 根据本地事务状态,重新 Commit 或者 Rollback

 
逻辑时序图

 

 

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

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

  1. 消费失败后进行一定次数的 重试

  2. 重试后也失败的话该消息丢进 死信队列 里

  3. 另外起一个线程监听消费 死信队列 里的消息,记录日志并且预警!

 

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

 

六、分布式事务场景样例

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

6.1. 引入依赖

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

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

 

6.2. 开启事务消息

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

 

6.3. 订单服务发送half消息

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

 

6.4. 订单服务监听half消息

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

  • executeLocalTransaction:用于提交本地事务

  • checkLocalTransaction:用于事务回查

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

 

6.5. 积分服务消费消息

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

 

6.6. 消费死信队列预警

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

 

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

 

往期精彩回顾

 

我就知道你“在看”

 

本文分享自微信公众号 - 陶陶技术笔记(zltrobin)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

优秀的个人博客,低调大师

微信关注我们

原文链接:https://my.oschina.net/zlt2000/blog/4522907

转载内容版权归作者及来源网站所有!

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

相关文章

发表评论

资源下载

更多资源
Mario,低调大师唯一一个Java游戏作品

Mario,低调大师唯一一个Java游戏作品

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Apache Tomcat7、8、9(Java Web服务器)

Apache Tomcat7、8、9(Java Web服务器)

Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、Sun 和其他一些公司及个人共同开发而成。因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web 应用服务器。

Eclipse(集成开发环境)

Eclipse(集成开发环境)

Eclipse 是一个开放源代码的、基于Java的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。幸运的是,Eclipse 附带了一个标准的插件集,包括Java开发工具(Java Development Kit,JDK)。

Sublime Text 一个代码编辑器

Sublime Text 一个代码编辑器

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。