消息中间件之RocketMQ源码分析(二十六)

本文详细阐述了RocketMQ中处理未发送事务结束消息的回查机制,包括回查服务的工作原理、关键变量如timeout和checkMax的定义,以及发送Half消息、Commit/Rollback操作和回查流程。特别关注了TransactionalMessageServiceImpl.check()方法的实现过程和回查条件判断。
摘要由CSDN通过智能技术生成

Broker回查事务消息

如果用户由于某种原因,在第二阶段中没有将endTransaction消息发送给Broker,Broker的Half消息又将如何处理。RocketMQ在设计时已经考虑到这个问题,通过"回查机制"处理第二阶段既未发送Commit
也没有发送Rollback的消息。回查是Broker发起的,Broker认为在接收Half消息后的一段时间内,如果生产者都没有发送Commit或Rollback消息给Broker,那么Broker会主动"询问"生产者该事务消息对应的本地事务执行结果,以此来决定事务是否要Commit.TransactionalMessageCheckService是回查服务的实现类
在这里插入图片描述
TransactionalMessageCheckService是一个线程服务,它在后台一直执行run()方法,run()方法一直调用waitForRunning()方法。关于waitForRunning()方法,这是RocketMQ的Broker中典型的"sleep"实现方式。该方式可以大致理解为"休息"一段时间再执行onWaitEnd()
方法,而TransactionalMessageCheckService服务重写了onWaitEnd()方法.
在这里插入图片描述

接下来分析下代码中的核心变量。

timeout

事务消息超时时间,如果消息在这个事件内没有进行Commit或Rollback,则执行第一次回查,默认6000ms
在这里插入图片描述

checkMax

最大回查次数,如果回查超过这个次数,事务消息将被忽略。回查的实现逻辑是每间隔一定时间执行TransactionalMessageServiceImpl#check()方法,判断哪些消息超时,对超时的消息开始执行回查

事务消息的最大回查次数默认15次
在这里插入图片描述

发送Half事务消息、执行Commit/Rollback命令、事务回查过程简图
在这里插入图片描述

  • RMQ_SYS_TRANS_HALF_TOPIC:保存事务消息的Topic,它存储
    用户发送的Half消息,有的消息已经进行了Rollback,有的消息
    状态是未知的
  • RMQ_SYS_TRANS_OP_HALF_TOPIC:也叫OP主题,当事务消息被Commit或Rollback后,会将原始事务消息的offset保存在该OP主题中
  • RMQ_SYS_TRANS_HALF_TOPIC和RMQ_SYS_TRANS_OP_HALF_TOPIC配合流程。
    首先,取出RMQ_SYS_TRANS_HALF_TOPIC中达到回查条件但没有回查过的消息,到RMQ_SYS_TRANS_OP_HALF_TOPIC主题中确认是否已经会回查,如果没有回查过则发起回查操作。

然后具体分析会回查方法TransactinalMessageServiceImpl.check()的实现过程。获取RMQ_SYS_TRANS_HALF_TOPIC主题的全部队列,依次循环每一个队列中的全部未消费的消息,确认是否需要回查。

对于每一条消息又是如何确认是否需要回查的呢?具体逻辑在TransactionalMessageServiceImpl#check()方法中的while(true)代码中
在这里插入图片描述

  • 第一步:回查前校验。如果当前回查执行的时间超过了最大允许的回查时间,(默认为60s)则跳出当前回查过程,如果当前回查的消息已经执行了Commit/Rollback,则忽略当前消息,直接回查下一条消息
    校验代码中的核心变量:
    MAX_PROCESS_TIME_LIMIT:回查时间限制,默认是60s且不能配置
    removeMap:该变量用于存储已经执行Commit/Rollback的Half消息位点
    i:当前回查的Half消息的位点值。如果当前Half消息在回查时,即在允许的回查时间内,又没有被生产者进行Commit/Rollback
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    填充removeMap的过程
  • 第二步:检查是否有消息需要回查。如果从RMQ_SYS_TRANS_HALF_TOPIC主题中获取Half消息为空的次数超过允许的最大次数或者没有消息,那么表示目前没有需要再回查的
    消息了,可以结束本次回查过程,当然如果传入的位点是非法的,则继续下一个回查的位点。代码中的核心参数:
    msgExt:Half消息对象
    getMessageNullCount:当前空消息的次数
    MAX_RETRY_COUNT_WHEN_HALF_NULL:表示可以允许的最大Half消息为空的次数,超过则结束回查,默认为1次,并且不能配置。
    messageQueue:RMQ_SYS_TRANS_HALF_TOPIC主题中正在被检查的队列如果RMQ_SYS_TRANS_HALF_TOPIC中已经没有待回查的消息,则立即终止当前的回查过程
    在这里插入图片描述
  • 第三步,回查次数校验,消息是否过期校验。如果Half消息回查次数已经超过了允许的最大回查次数,则不再回查,实现该校验的方法是TransactionMessageServiceImpl.needDisard();如果Half消息对应的CommitLog已经过期,那么也不回查,该校验实现的方法是
    TransactionalMessageServiceImpl.needSkip()
    在这里插入图片描述
    在这里插入图片描述
  • 第四步:新发送的Half消息不用回查,对于不是新发送的Half消息,如果在免疫回查时间(免疫期)内,也不用回查。免疫期是指生产者在发送Half消息后、执行Commit/Rollback前,Half消息都不需要回查,这段时间就是这个Half消息的回查免疫期。免疫期的判断逻辑如图。代码中的核心变量如下:
    valueOfCurrentMinusBorn:当前时间减去消息的发送时间
    checkImmunityTimeStr:用户设置的消息回查免疫时间,换言之,就是生产者本地事务的最长执行时间,也就是默认6s.
    当checkImmunityTimeStr和transactionTimeout同时存在时,免疫时间将通过getImmunityTime(checkImmunityTimeStr, transactionTimeout)方法计算后可以得出最终的免疫期,进而进行免疫期回查判断
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 第五步:最终判断是否需要回查生产者本地事务执行结果,满足图中条件之一就可以进行回查:
    1.如果没有OP消息,并且当前Half消息在免疫期外
    2.当前Half消息存在OP消息,并且最后一个本批次OP消息中的最后一个消息在免疫期外,也就是满足回查时间
    3.Broker与客户端有时间差
    4.重新将当前Half消息存储在RMQ_SYS_TRANS_HALF_TOPIC主题中,原因是回查是一个异步过程,Broker不确定回查的结果是成功还是失败,所以RocketMQ做最坏的打算,如果回查失败则下次继续回查;如果本地回查成功则写入OP消息,下次再读取Half消息时也不会回查

在这里插入图片描述

  • 第六步:执行回查。在当前批次的Half消息回查完毕后,更新Half主题和OP主题的消费位点,推进回查进度。Broker将回查消息通过回查线程池异步地发送给生产者,执行事务结果回查
    在这里插入图片描述
    在这里插入图片描述
  • 22
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

coffee_babe

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值