RocketMQ源码解析之消息生产者(事务消息原理篇)

前言

之前我们解析了RocketMQ消息生产者发送普通消息的流程,其实事务消息跟普通消息差不多,它也是使用了同步发送的方式,只不过它引入了一个half消息的概念,这东西对用户是透明的,如果单单是编程的话不需要过多的关心,接下来我先介绍下RocketMQ事务消息发送的一个编程模型,知道RocketMQ是怎样发送事务消息的,然后就是使用介绍它的实现原理,最后就是进行消息生产者端的源码解析,其实事务消息很多事情都是broker来做的,本篇提及到原理,不做broker源码级别的解析,然后解析broker源码的时候会具体介绍。

1. 怎样发送一个事务消息

首先我们要了解RocketMQ事务消息的使用场景,分布式事务分为刚性事务跟柔性事务,刚性事务就是那种强一致性的那种,说成功必须都要同时成功,说失败必须都要同时回滚,柔性事务就比较宽松了,只需要达到最终一致性就可以了,比如说使用mq做最大努力通知型,RocketMQ事务消息就是属于柔性事务。
接下来我们来看下我们怎样发送一个RocketMQ事务消息(这里直接拿RocketMQ源码example项目里的事务发送例子)
在这里插入图片描述
我们一行行解释下:
第一行,创建一个事务listener 对象,这个事务listener 需要你自己去实现 TransactionListener 接口,然后它里面有2个方法需要我们自己实现
在这里插入图片描述
一个是执行本地事务,一个是检查本地事务的,这个我们稍后将原理流程的时候再解释。
第二行,这个不用说,就是创建一个事务消息的producer对象
第三行,这行一看就是创建一个线程池,这个线程池其实就是执行 上面那个事务listener 里面 检查本地事务方法用的。
接着就是将listener与 checkThreadPool 设置到producer中,启动producer
接着往下就是创建消息了,这个消息需要我们注意的有个keys。
再就是发送消息了,这里发送消息用的sendMessageInTransaction 方法,可以看到有2个方法,第一个是msg ,这个不用说,第二个参数args我们后面会介绍。

2. RocketMQ事务消息流程与原理介绍

在第一节我们介绍了一下RocketMQ应该怎样编程,但是里面很多东西都不知道什么意思,接下来我们会详细介绍一下RocketMQ的执行流程与原理。
我们在使用RocketMQ做事务消息的时候,需要先发送我们的事务消息,然后当我们事务消息发送成功之后,在执行本地事务,本地事务执行成功,就需要提交事务消息,如果失败,就回滚事务消息。
下面我们就详细介绍下这个流程
我们就那支付成功,发送用户积分这个案例来说吧,我们有这么一个场景,假设我们在做一个电商项目, 然后当用户下单并支付成功的时候,会根据用户支付的金额来计算并向用户放一定的积分,我们这个发放积分动作不能拖累我们的支付动作,不能因为这种枝叶业务影响我们支付主业务的体验, 所以我们将发放积分的需求使用RocketMQ的事务消息来完成。

一个用户下了单,然后这个时候到了支付阶段了,那么我们先根据用户提交过来的订单,计算好要给用户发放的积分,封装Message,进行消息发送,我们将本地事务流程放到 我们自己实现的listener的executeLocalTransaction 方法,当事务消息发送到RocketMQ的时候,然后它就会调用executeLocalTransaction 方法来执行本地事务,也就是支付流程,如果用户支付成功,并写入支付记录,修改了订单状态 提交事务之后 执行 return LocalTransactionState.COMMIT_MESSAGE 提交事务消息, 如果支付失败了就return LocalTransactionState.ROLLBACK_MESSAGE 回滚事务消息,这个其实就是告诉RocketMQ这个本地事务成功了或者失败了,需要进行消息的提交或者回滚动作
这里有几个点需要注意下:
(1)我在executeLocalTransaction执行本地事务,我需要的参数应该怎么传递,比如需要支付的订单…一堆东西,这个参数传递是在发送消息的时候传递的,也就是第一节那个args 。
(2)如果我发送消息失败了怎么处理,发送消息失败就抛出异常,就不用走支付流程了。
(3) 如果我提交了本地事务,然后在告诉RocketMQ事务状态的时候,服务挂了,或者网络波动,RocketMQ的broker没有收到我得提交消息怎么办?这个也不用担心,我们listener 还有一个方法checkLocalTransaction 这个方法就是用来检查我们本地事务的,我们上面那个线程池就是干这个事情的,执行checkLocalTransaction 方法的,这个方法就是询问你本地事务执行结果是什么样的,这里应该怎样做呢?其实你可以在执行本地事务那个方法里面将msg的一个事务id记录下来,与你这个支付记录关联起来,到时候RocketMQ来询问你这个本地事务状态的时候,它会将那个msg传过来,msg里面有个事务id,你可以拿着这个事务id去查找你这个支付记录,看看支付状态,然后告诉RocketMQ是提交事务还是回滚事务。
好了,到这我们就将RocketMQ事务流程解释完成了。

接下来介绍一下原理
(1)我们发送这个事务消息的时候一开始并不是直接发送到你指定的那个topic 对应的队列里面的,而是将消息发送到RMQ_SYS_TRANS_HALF_TOPIC topic里面,然后它返回响应 告诉生产者,执行executeLocalTransaction 方法来执行本地事务,为啥不放了你设置的那个 topic里?就是防止消费者给消费了,这个时候还不知道你本地事务执行情况,就给消费了岂不是很尴尬。
(2)当你本地事务执行成功,返回 commit提交事务,这个时候broker 会 先从RMQ_SYS_TRANS_HALF_TOPIC topic里面找到你那个消息,恢复原来的样子,然后进行存储,这个时候存储就存储到了 你设置到的那个topic里面了。存储成功之后将 形成一个删除消息 然后放到RMQ_SYS_TRANS_OP_HALF_TOPIC topic 里面。放到你原来那个topic里面,你的消费者就可以消费了
(3)如果你本地事务失败,然后就要rollback 了,这个时候先从RMQ_SYS_TRANS_HALF_TOPIC topic里面找到你那个消息,然后形成一个删除消息 然后放到RMQ_SYS_TRANS_OP_HALF_TOPIC topic 里面。
(4)出现网络问题或者服务挂了怎么办?
如果你在发送消息的时候出现了问题,消息是使用同步发送,然后会重试,然后会抛出异常,发送失败,你的本地事务也就不用执行了。
如果你告诉broker 提交事务或者回滚事务的时候出现了问题怎么办?这时候broker 会有个事务服务线程,隔一段时间就扫描RMQ_SYS_TRANS_HALF_TOPIC topic 里面没有提交或者回滚的消息,然后它就会发送消息到你的生产者端来,然后执行checkLocalTransaction 这个检查事务的方法,询问你事务的执行状态。它默认会问你15次,15次没结果就直接删了,估计是绝望了。

3. 总结

本文先是介绍了 RocketMQ 事务消息生产者端应该怎样写,然后又介绍了事务消息的执行流程,最后介绍了RocketMQ的存储原理与执行原理,好了,到这我们RocketMQ消息生产者 事务消息原理篇就介绍完了,我们后面会分析下这个事务消息生产者源码。

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页