RocketMQ 源码学习--Consumer-03 消息拉取方式源码解析

前提

  • 之前学习了 Push 的方式,底层也是 Pull 模式,那么 Push 和 Pull 模式有什么区别吗。简单理解 Push 模式和 Pull 模式

    • 推模式:消息发送者将消息发送到Broker,然后Broker主动推送给订阅了该消息的消费者。
    • 拉模式:消息发送者将消息发送到Broker上,然后由消息消费者自发的向Broker拉取消息。
  • RocketMQ 中的退模式,严格意义上来讲,RocketMQ 并没有实现 PUSH 模式,而是对拉模式进行一层包装,在 RebalaceImpl 的时候产生拉取请求,在消费端开启一个线程 PullMessageService 循环向 Broker拉取消息,一次拉取任务结束后马上又发起另一次拉取操作,实现准实时自动拉取

在 22 年之前,拉取的处理类是 DefaultMQPullConsumer,现在改成了 DefaultMQLitePullConsumer,为啥要改呢,从名字上来看,应该比之前的额拉取服务更低的资源损耗,后续研究一波

源码

RocketMQ 拉模式,RocketMQ 消费者不自动向消息服务器拉取消息,而是将控制权移交给应用程序,RocketMQ消费者只是提供拉取消息API。怎么理解呢,就是最基本的拉取,你如果需要循环拉取,就给个循环,一切看用户使用方。

重要属性

java 复制代码
public class DefaultLitePullConsumerImpl implements MQConsumerInner {
      //负载均衡类
      private RebalanceImpl rebalanceImpl = new RebalanceLitePullImpl(this);
}

回想一下 Push

  1. 当 Rebalace 检测到节点分布发生变化,就会窗机 PullRequest
  2. PullMessageServer 线程获取到 PullRequest 不断的去拉取消息,拉取完,继续放入队列中,达到不断拉取的效果

对于 Pull 这个平衡类,难道也向里面加入请求吗,如果加入就和 Push 没啥区别了,直接看里面的方法,从下面,可以看出,并不会将请求加入到队列中,那么也就不会和 Push 拉取消息,消费消息

scala 复制代码
public class RebalanceLitePullImpl extends RebalanceImpl {
    //为空
    @Override
    public void dispatchPullRequest(List<PullRequest> pullRequestList) {
    }
}

重要方法

start
java 复制代码
public synchronized void start() throws MQClientException {
    switch (this.serviceState) {
        case CREATE_JUST:
            this.serviceState = ServiceState.START_FAILED;
​
            this.checkConfig();
​
            if (this.defaultLitePullConsumer.getMessageModel() == MessageModel.CLUSTERING) {
                this.defaultLitePullConsumer.changeInstanceNameToPID();
            }
​
            //K1 将该消费者加入到 MQClientInstance 消费者列表中
            initMQClientFactory();
​
            //K1 填充 rebalanceImpl 对象的消费组、消息队列分配器、消费模式
            initRebalanceImpl();
​
            //K1 构建 PullAPIWrapper 对象,该对象封装了具体拉取消息的逻辑,PULL,PUSH 模式最终都会调用 PullAPIWrapper 类的方法从 Broker 拉取消息
            initPullAPIWrapper();
​
            //K1 根据集群消费模式(广播、集群)初始化消息进度管理器offsetStore
            initOffsetStore();
​
            mQClientFactory.start();
​
            startScheduleTask();
​
            this.serviceState = ServiceState.RUNNING;
​
            log.info("the consumer [{}] start OK", this.defaultLitePullConsumer.getConsumerGroup());
​
            operateAfterRunning();
​
            break;
        case RUNNING:
        case START_FAILED:
        case SHUTDOWN_ALREADY:
            throw new MQClientException("The PullConsumer service state not OK, maybe started once, "
                + this.serviceState
                + FAQUrl.suggestTodo(FAQUrl.CLIENT_SERVICE_NOT_OK),
                null);
        default:
            break;
    }
}
  • 问题

    • 既然 Pull 模式无需自动拉取消息,但 PullMessageService 线程(消息拉取)+ RebalanceService 线程(消息队列负载)这个两个线程就没必要启动,这里启动了,会不会带来问题?

      • 其实上面已经解答了,根本就不会加入 PullRequest,那么也就不会加入到 PullRequestQueue 中。而且从 PullMessageService 的代码也可以看出,所有的PullRequest 都是 PushConsumer 产生的
      java 复制代码
      private void pullMessage(final PullRequest pullRequest) {
        //IMP 通过 PullRequest 获取消费者,但是对于 PullService 而言,不会创造 PullRequest,所以,此处所有的都是 PushConsumer
        final MQConsumerInner consumer = this.mQClientFactory.selectConsumer(pullRequest.getConsumerGroup());
        if (consumer != null) {
          DefaultMQPushConsumerImpl impl = (DefaultMQPushConsumerImpl) consumer;
          impl.pullMessage(pullRequest);
        } else {
          log.warn("No matched consumer for the PullRequest {}, drop it", pullRequest);
        }
      }
  • ReblanceService 线程默认每 20s 进行一次消息队列重新负载,判断消息队列是否需要进行重新分布(如果消费者个数和主题的队列数没有发生改变),则继续保持原样。对于 PULL 模型,如果消费者需要监听某些主题队列发生事件,注册消息队列变更事件方法,则 RebalanceService 会将消息队列负载变化事件通知消费者。

  • 至于 PULL 模式那些根据消息队列拉取消息的方法,与 PUSH 模式走的逻辑是一样的,唯一的区别是PULL 模式是需要应用程序收到触发消息拉取动作。

  • 通过上述分析,我们总结一下RocketMQ,PUSH,PULL模式区别:

    • PUSH: 消费者订阅主题,然后自动进行集群内消息队列的动态负载,自动拉取消息。准实时。
    • PULL:消费者无需订阅主题,由业务方(应用程序)直接根据MessageQueue拉取消息。

项目中一般采用PUSH模式。

学习引入链接:blog.csdn.net/prestigedin...

相关推荐
老任与码10 分钟前
Spring AI Alibaba(1)——基本使用
java·人工智能·后端·springaialibaba
华子w90892585941 分钟前
基于 SpringBoot+VueJS 的农产品研究报告管理系统设计与实现
vue.js·spring boot·后端
星辰离彬1 小时前
Java 与 MySQL 性能优化:Java应用中MySQL慢SQL诊断与优化实战
java·后端·sql·mysql·性能优化
GetcharZp2 小时前
彻底告别数据焦虑!这款开源神器 RustDesk,让你自建一个比向日葵、ToDesk 更安全的远程桌面
后端·rust
jack_yin3 小时前
Telegram DeepSeek Bot 管理平台 发布啦!
后端
小码编匠3 小时前
C# 上位机开发怎么学?给自动化工程师的建议
后端·c#·.net
库森学长3 小时前
面试官:发生OOM后,JVM还能运行吗?
jvm·后端·面试
转转技术团队3 小时前
二奢仓店的静默打印代理实现
java·后端
蓝易云3 小时前
CentOS 7上安装X virtual framebuffer (Xvfb) 的步骤以及如何解决无X服务器的问题
前端·后端·centos
秋千码途4 小时前
小架构step系列07:查找日志配置文件
spring boot·后端·架构