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...

相关推荐
凡人的AI工具箱2 小时前
AI教你学Python 第11天 : 局部变量与全局变量
开发语言·人工智能·后端·python
是店小二呀2 小时前
【C++】C++ STL探索:Priority Queue与仿函数的深入解析
开发语言·c++·后端
canonical_entropy2 小时前
金蝶云苍穹的Extension与Nop平台的Delta的区别
后端·低代码·架构
我叫啥都行3 小时前
计算机基础知识复习9.7
运维·服务器·网络·笔记·后端
无名指的等待7123 小时前
SpringBoot中使用ElasticSearch
java·spring boot·后端
.生产的驴4 小时前
SpringBoot 消息队列RabbitMQ 消费者确认机制 失败重试机制
java·spring boot·分布式·后端·rabbitmq·java-rabbitmq
AskHarries4 小时前
Spring Boot利用dag加速Spring beans初始化
java·spring boot·后端
苹果酱05675 小时前
一文读懂SpringCLoud
java·开发语言·spring boot·后端·中间件
掐指一算乀缺钱5 小时前
SpringBoot 数据库表结构文档生成
java·数据库·spring boot·后端·spring
计算机学姐7 小时前
基于python+django+vue的影视推荐系统
开发语言·vue.js·后端·python·mysql·django·intellij-idea