RocketMQ 消费端如何监听消息?

本文详细解析RocketMQ消费者如何监听消息,通过源码跟踪,介绍从消息拉取到消费提交的整个流程,包括核心模块消息拉取、拉取流程、消息处理和消费进度提交等关键步骤。
摘要由CSDN通过智能技术生成

前言

大家好,我是小郭,上一篇文章中我们主要来看RocketMQ消息消费者是如何启动的,

那他有一个步骤是非常重要的,就是启动消息的监听,通过不断的拉取消息,来实现消息的监听,

那具体怎么做,让我们我们跟着源码来学习一下~

流程地图

源码跟踪

这一块的代码比较多,我自己对关键点的一些整理,这个图我画的不是很OK

核心模块(消息拉取)

入口:this.pullMessageService.start();

  1. 执行线程池run方法,轮流从pullRequestQueue中获取PullRequest

org.apache.rocketmq.client.impl.consumer.PullMessageService#run

声明一个阻塞队列用来存放 PullRequest 对象

PullRequest 用于消息拉取任务,如果 pullRequestQueue 为空则会阻塞,直到拉取任务被放入

private final LinkedBlockingQueue<PullRequest> pullRequestQueue = new LinkedBlockingQueue<PullRequest>();
复制代码

将 stopped 用volatile来修饰,每次执行的时候都检测stopped的状态,线程只要修改了这个状态,其余线程就会马上知道

protected volatile boolean stopped = false;
@Override
public void run() {
    log.info(this.getServiceName() + " service started");
    // 判断启动状态
    while (!this.isStopped()) {
        try {
            // 取出一个PullRequest对象
            PullRequest pullRequest = this.pullRequestQueue.take();
            this.pullMessage(pullRequest);
        } catch (InterruptedException ignored) {
        } catch (Exception e) {
            log.error("Pull Message Service Run Method exception", e);
        }
    }

    log.info(this.getServiceName() + " service end");
}
复制代码
  1. 获取消费队列快照,判断状态是否正常,同时更新最后一次拉取时间

PullMessageService 从消息服务器默认拉取32条消息,按消息的偏移量顺序存放在 ProcessQueue 队列

final MQConsumerInner consumer = this.mQClientFactory.selectConsumer(pullRequest.getConsumerGroup());
复制代码

入口:org.apache.rocketmq.client.impl.consumer.DefaultMQPushConsumerImpl#pullMessage

// 获取消费队列快照
final ProcessQueue processQueue = pullRequest.getProcessQueue();
if (processQueue.isDropped()) {
    log.info("the pull request[{}] is dropped.", pullRequest.toString());
    return;
}

// 设置最后一次拉取时间
pullRequest.getProcessQueue().setLastPullTimestamp(System.currentTimeMillis());
复制代码
  1. 校验客户端运行状态
// 校验状态
this.makeSureStateOK();
private void makeSureStateOK() throws MQClientException {
    if (this.serviceState != ServiceState.RUNNING) {
        throw new MQClientException("The consumer service state not OK, "
            + this.serviceState
            + FAQUrl.suggestTodo(FAQUrl.CLIENT_SERVICE_NOT_OK),
            null);
    }
}
复制代码

如果消费者状态不正确,则抛出异常,启动定时线程池过段时间回收 PullRequest 对象,以便pullMessageService能及时唤醒并再次执行消息拉取,这个逻辑在多个地方使用到了

public void executePullRequestLater(final PullRequest pullRequest, final long timeDelay) {
    if (!isStopped()) {
        this.scheduledExecutorService.schedule(new Runnable() {
            @Override
            public void run() {
                PullMessageService.this.executePullRequestImmediately(pullRequest);
            }
        }, timeDelay, TimeUnit.MILLISECONDS);
    } else {
        log.warn("PullMessageServiceScheduledThread has shutdown");
    }
}
复制代码
public void executePullRequestImmediately(final PullR
RocketMQ消费可以通过设置重试次数和延时等级来实现消息消费失败后的重试。一般情况下,我们可以通过以下两种方式来设置重试次数和延时等级: 1. 使用ConsumerConfig类中的setConsumeRetryTimes()方法和setDelayLevelWhenNextConsume()方法来设置重试次数和延时等级。例如: ``` ConsumerConfig consumerConfig = new ConsumerConfig(); consumerConfig.setConsumeRetryTimes(3);//设置重试次数 consumerConfig.setDelayLevelWhenNextConsume(1);//设置延时等级 ``` 2. 在消费者的监听器中通过设置ConsumeConcurrentlyContext对象的属性来设置重试次数和延时等级。例如: ``` @Override public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) { for (MessageExt msg : msgs) { try { //消费消息 //... return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; } catch (Exception e) { //消息消费失败,进行重试 if (context.getRetryTimes() < 3) {//设置重试次数 context.setDelayLevelWhenNextConsume(1);//设置延时等级 return ConsumeConcurrentlyStatus.RECONSUME_LATER; } else { //重试次数达到上限,记录日志 //... return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; } } } return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; } ``` 需要注意的是,在RocketMQ中,延时等级是通过设置消息的delayTimeLevel属性来实现的。当消息消费失败后,RocketMQ会根据设置的延时等级来计算下一次消费的时间。因此,在设置延时等级时,需要根据业务需求和消息重要性进行适当的选择。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值