RocketMQ消息消费-消费者客户端是如何处理已经拉取到的消息

196 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情

往期回顾

RocketMQ源码解析-消息是如何写入Broker服务器(客户端篇)

RocketMQ源码解析-消息是如何写入Broker服务器(Broker端篇)

RocketMQ源码解析-步步拆解ConsumeQueue的写入流程

RocketMQ消息写入-步步拆解IndexFile的写入流程

RocketMQ消息消费-客户端拉取消息前的准备工作

RocketMQ消息消费-客户端为拉取消息所做的努力

RocketMQ消息消费-服务端如何回应消息的拉取请求

我们已经相继梳理了多篇关于RocketMQ的技术文章。这些文章站在源码的角度,以图文并发的方式讲解了消息的生产发送、消息的存储、消息的消费。

本篇文章继续讲解RocketMQ消息消费。主要梳理了消费者客户端在拉取到Broker端的消息后,是如何处理这些消息的,又是如何回调到我们自己封装的业务逻辑的。本篇文章仍然采用按照步骤拆解源码的方式进行,并在关键点处给出了对于源码的详细解释,有助于读者更好的理解以及掌握这部分内容。

源码解析

pullMessageAsync方法是在客户端拉取消息时调用的方法,通过其方法名字可知,pullMessageAsync是异步方法,不会阻塞执行线程。

将消息拉取的请求通过remotingClient.invokeAsync方法发往Broker端,等到Broker端处理完毕并响应后,会回调InvokeCallback的operationComplete方法,来处理Broker对于本次消息拉取请求的响应。

通过processPullResponse方法将RemotingCommand对象解析成PullResult,并回调onSuccess,继而开启客户端的处理流程。我们本篇的文章就是从此处开始,重点关注一下消费者客户端是如何处理已经拉取到的消息。

image.png

PullCallback就是在上面用到的那个回调对象,定义了两个方法,一个是onSuccess,另一个是onException。

我们重点关注一下在getPullStatus是FOUND时的处理逻辑。源码中涉及的重点逻辑已经给出了注释,可以结合起来一起分析。

这段逻辑中,我们重点跟踪两个方法,一个是pullAPIWrapper.processPullResult,主要用于将拉取到的消息反序列化为实体对象并进行Tags过滤,另一个是 consumeMessageService.submitConsumeRequest,主要用于将拉取到的消息进行拆解,放入线程池中进行消费。

image.png

processPullResult方法先将拉取到的消息进行反序列化成MessageExt对象,然后进行Tag的详细过滤,返回PullResult对象对这些内容进行封装。

image.png

submitConsumeRequest将拉取到的消息进行拆解,放入到客户端的消费线程池中进行消费。

消费分为并发消费和顺序消费,本篇文章的梳理只关注常用的并发消费。

ConsumeRequest是一个实现了Runnable接口的实现类,并且通过其构造方法附加了要处理的消息以及队列的相关属性,在线程池中将会调用ConsumeRequest的run方法对消息进行处理。

image.png

可以从run方法中看到,调用到了我们自定义的业务监听器对消息进行了处理,并返回了处理状态status。

这段逻辑就将我们自定义的业务处理器与RocketMQ的客户端框架串联了起来。

这个ConsumeRequest中的消息经过我们业务逻辑处理完之后,又该何去何从呢。接下来我们重点看一下ConsumeMessageConcurrentlyService.this.processConsumeResult这个方法,这个方法就是解决我们提出来的疑惑的。

image.png

关于消费模式,我们只关注集群模式即可。

总体来看就是处理了两件事情:

  1. 消息失败的消息,就需要进行重新的消费,如何进行重新的消费呢,就是将这些消费失败的消息重新发往Broker服务器,并设置相应的延迟消息级别等相关的信息。

  2. 更新消费位点也即是offset偏移量。

image.png

看一下removeMessage方法的源码,再结合给出的代码注释,可以了解到RocketMQ保障了不丢失消息,但是可能会消费重复的消息,需要考虑幂等性操作。

image.png

结尾总结

对于消费者客户端来说,消息的拉取以及消费周而复始的重复着这一系列的动作。希望本篇文章能够对读者的工作以及学习提供一些力所能及的帮助,相信读者看完本篇文章后,再结合源码深入的研究一番,应该能更好的掌握消息者客户端的处理流程。