1、事务实现实战活动中心场景介绍 在电商系统上线初期,消息项目往往会进行一些“拉新”活动,应用原理例如活动部门提出新用户注册送积分、场景送优惠券活动。事务实现实战 基于分布式、消息项目微服务的应用原理设计理念,通常的场景架构设计(子系统交互)如下图所示: 其核心系统介绍如下: 提供用户登录、用户注册等服务,事务实现实战一个新用户注册时,消息项目向MQ服务器中的应用原理USER_REGISTER主题发送一条消息,主流程结束,场景与送积分,事务实现实战送优惠券等过程解耦。消息项目 提供发放优惠券、应用原理使用优惠券等与券相关的基础服务。 提供积分相关的服务,例如积分赠送、积分消费、积分查询等基础服务。 订阅MQ,按照规则决定是否需要赠送积分,如果需要则调用积分相关的基础接口,完成积分的发放。 订阅MQ,按照规则决定是源码下载否需要赠送优惠券,如果需要则调用券系统相关的基础接口,完成优惠券的发放。 上面的架构设计非常优雅,但并不是无懈可击,读者们肯定会想到如果新用户注册成功,但消息发送到MQ失败,或者消息成功发送到MQ,但发送完MQ后系统出现异常导致用户注册失败又该如何呢? 上面的问题其实就是典型的分布式事务问题:即如何保证用户注册(数据库操作)与MQ消息发送这两个分布式操作的一致性。 RocketMQ事务消息闪亮登场。 2、事务消息实现原理 一言以蔽之:RocketMQ事务消息要解决的问题是消息发送与业务的一致性,其解决思路:二阶段提交与事务状态回查,其具体实现流程如下图所示: 其核心设计理念: 在具体实践中,消息发送者在无法获取事务状态时不要武断的返回ROLLBACK,而是要返回UNOWN,亿华云让服务端定时重试回查,说明如下: 在将PREPARE消息发送到Broker后,服务端发起事务查询时本地事务可能还未提交,为了避免无效的事务回查机制,RocketMQ通常至少在收到PREPARE消息6s后才会发起第一次事务回查,可通过 transactionTimeOut 配置。故客户端在实现事务回查时无法证明事务状态时不应该返回ROLLBACK,而是返回UNOWN。 3、事务消息实战 光说不练假把式,接下来以一个新用户注册送优惠券的场景来详细介绍如何使用事务消息。 项目模块职责说明如下: 事务消息的核心代码组装在transaction-service,其核心类图如下: 其中核心要点如下: Dubbo接口业务实现类,类似MVC的控制层,在这里做一些参数验证,但不执行具体的业务逻辑,只是发送一条事务消息到MQ。 事务监听器,在 executeLocalTransaction 方法中执行业务逻辑,数据库本地事务加在该方法。 温馨提示:之所以不在UserServicveImpl中执行本地事务,是因为 executeLocalTransaction 中抛出的异常会被RocketMQ框架捕捉,及异常无法被UserServiceImpl感知,即无法实现其事务的一致性。 接下来展示其核心代码,全部源码已上传到github仓库。 仓库地址:https://github.com/dingwpmz/rocketmq-learning 3.1 UserServiceImpl 核心实现 UserServiceImpl 的核心要点如下: 3.2 UserRegTransactionListener 核心实现 事务监听器需要实现执行本地事务与事务回查两个接口。 3.2.1 实现 executeLocalTransaction 首先需要实现 executeLocalTransaction 方法,执行本地事务,其代码如下图所示: 其中几个关键点说明如下: 3.2.2 实现 checkLocalTransaction 其次需要实现事务状态回查,用来RocketMQ服务端感知事务是否成功,其实现原理如下图所示: 其实现关键点如下: 3.3 代码获取 上文只是将事务消息的核心代码加以解读,并重点阐述每个步骤的实现关键点,笔者基于SpringBoot,尝试结合场景学习RocketMQ的使用技巧,其代码上传到了github仓库。 https://github.com/dingwpmz/rocketmq-learning 丁威,《RocketMQ技术内幕》作者,RocketMQ社区优秀布道师,主打成体系分享JAVA主流中间件,打造完备的互联网架构体系,目前涵盖Java并发、微服务、消息、调度、数据异构等领域,未来继续关注监控、在线诊断等领域。 本文转载自微信公众号「中间件兴趣圈」,可以通过以下二维码关注。转载本文请联系中间件兴趣圈公众号。