news 2026/10/15 14:55:21

RocketMQ架构:推模式与拉模式

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
RocketMQ架构:推模式与拉模式

RocketMQ 的推模式、拉模式,到底有什么区别?

RocketMQ 客户端提供了DefaultMQPushConsumer和DefaultLitePullConsumer两种 API,但底层都是拉取模型。所谓 Push,本质上是“封装好的、带流控的长轮询拉取”。

一、经典推拉模型

这里讨论的是 Consumer 与 Broker 之间的交互,不是 Producer 与 Broker。

经典推模式

Broker 收到消息后主动推送给 Consumer。Consumer 被动接收。

缺点很明显:当 Broker 推送速度超过消费能力时,Consumer 会内存积压,甚至 OOM。因此经典推模式只适合消息量不大、消费能力强的场景。

经典拉模式

Consumer 主动向 Broker 拉取消息,消费多少拉多少。消费不过来时可以暂停或降低频率。

代价是可能引入消息延迟和 Broker 端积压。RocketMQ 和 Kafka 都选择拉模型,所以必须做好积压监控。

二、RocketMQ 的 PushConsumer 本质还是拉

客户端实例会启动多个异步服务:

  • RebalanceService:负责队列再平衡,生成PullRequest;
  • PullMessageService:从pullRequestQueue取请求并拉取消息;
  • ConsumeMessageOrderlyService或ConsumeMessageConcurrentlyService:消费消息。

拉取消息前会做流控。如果缓存消息超过 1000 条或 100MB,就延迟 50 毫秒再拉:

if(cachedMessageCount>this.defaultMQPushConsumer.getPullThresholdForQueue()){this.executePullRequestLater(pullRequest,PULL_TIME_DELAY_MILLS_WHEN_FLOW_CONTROL);return;}

这就是 RocketMQ Push 和经典 Push 的关键区别:不是 Broker 无脑推送,而是客户端根据自身消费能力主动控制拉取节奏。

三、Broker 没有消息时怎么办

如果 Broker 暂时没有消息,客户端不会高频空转,而是进入长轮询等待。

客户端收到NO_NEW_MSG后,会把请求重新放回队列:

caseNO_NEW_MSG:pullRequest.setNextOffset(pullResult.getNextBeginOffset());DefaultMQPushConsumerImpl.this.correctTagsOffset(pullRequest);DefaultMQPushConsumerImpl.this.executePullRequestImmediately(pullRequest);break;

Broker 端的PullRequestHoldService会定期检查是否有新消息。默认每 5 秒检查一次,长轮询整体等待时间约 30 秒。如果 CommitLog 有新数据,还会主动唤醒请求,做到准实时。

四、PUSH 模式的应用开发

官方示例大致如下:

DefaultMQPushConsumerconsumer=newDefaultMQPushConsumer("CID_JODIE_1");consumer.subscribe("TopicTest","*");consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);consumer.registerMessageListener(newMessageListenerConcurrently(){@OverridepublicConsumeConcurrentlyStatusconsumeMessage(List<MessageExt>msgs,ConsumeConcurrentlyContextcontext){System.out.printf("%s Receive New Messages: %s %n",Thread.currentThread().getName(),msgs);returnConsumeConcurrentlyStatus.CONSUME_SUCCESS;}});consumer.start();

用户只需要注册监听器,拉取过程由客户端内部的线程完成。

五、PULL 模式的应用开发

DefaultLitePullConsumer的用法更接近业务自己控制拉取:

DefaultLitePullConsumerlitePullConsumer=newDefaultLitePullConsumer("lite_pull_consumer_test");litePullConsumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);litePullConsumer.subscribe("TopicTest","*");litePullConsumer.start();while(running){List<MessageExt>messageExts=litePullConsumer.poll();System.out.printf("%s%n",messageExts);}

更完整的同步拉取示例:

DefaultMQPullConsumerconsumer=newDefaultMQPullConsumer("group1_pull");consumer.setNamesrvAddr("localhost:9876");consumer.start();Set<MessageQueue>messageQueues=consumer.fetchSubscribeMessageQueues("topic1");intmaxNums=10;while(true){booleanfound=false;for(MessageQueuemessageQueue:messageQueues){longoffset=consumer.fetchConsumeOffset(messageQueue,false);PullResultpullResult=consumer.pull(messageQueue,"tag8",offset,maxNums);switch(pullResult.getPullStatus()){caseFOUND:found=true;List<MessageExt>msgs=pullResult.getMsgFoundList();for(MessageExtmsg:msgs){// 处理消息}consumer.updateConsumeOffset(messageQueue,pullResult.getNextBeginOffset());break;caseNO_NEW_MSG:break;caseNO_MATCHED_MSG:break;caseOFFSET_ILLEGAL:break;}}if(!found){TimeUnit.MILLISECONDS.sleep(5000);}}

PULL 模式中,拉取时机、拉取位置、消费进度都由业务控制。

六、Push 与 Pull 怎么选

维度PushConsumerPullConsumer
开发成本低,只需注册监听器高,需要自己管理队列和 offset
可控性低,拉取由客户端内部线程负责高,可自主决定拉取时机和位置
流控客户端内部自动流控业务自己控制
适用场景大多数常规消费场景需要精确控制消费位点和批量的场景

如果只是常规消费,优先用 PushConsumer。如果要做复杂批处理、按指定 offset 消费、精确控制吞吐,可以选择 PullConsumer。

七、总结

RocketMQ 的 Push 不是 Broker 主动推送,而是客户端通过 RebalanceService、PullMessageService 和消费线程共同完成的自动拉取。它用流控避免消息在消费端堆积。

Pull 模式把更多控制权交给业务,代价是要自己处理队列、offset 和重试。理解这两种模式的关键,是看清“拉取请求从哪来、消费线程怎么触发、流控发生在哪里”。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/15 14:55:15

电力系统多重故障识别:随机化学算法与MATLAB实现

1. 项目背景与核心挑战电力系统作为现代社会的命脉&#xff0c;其安全稳定运行直接关系到国民经济和人民生活。近年来&#xff0c;随着新能源大规模并网和电网结构日益复杂&#xff0c;连锁故障引发的停电事故频发&#xff0c;给社会带来巨大损失。2019年某区域电网因多重故障引…

作者头像 李华
网站建设 2026/10/15 14:54:28

为AI代理装上安全锁:OpenClaw接入E2B沙箱实践

你有没有想过&#xff0c;一个能帮你自动操作系统、读写文件、调用各种工具的AI代理&#xff0c;一旦被别有用心的人或数据诱导&#xff0c;它能做出什么事&#xff1f;我见过太多人只关注AI代理"能力多强"&#xff0c;却忽略了它"闯祸能力同样强"这个事实…

作者头像 李华
网站建设 2026/10/15 14:54:04

温度表打印

#include<stdio.h> int main() {int f;float c;for(f0;f<200;f20){c(5/9.0)*(f-32);printf("%d %.0f\n",f,c);}return 0; }

作者头像 李华
网站建设 2026/10/15 14:53:48

Docker网络原理与排障:从docker0网桥到veth-pair实战

1. 项目概述&#xff1a;为什么Docker网络不是“配个IP就完事”的事刚接触Docker的人&#xff0c;十有八九会卡在“容器连不上”这一步——明明docker run -p 8080:80 nginx跑起来了&#xff0c;浏览器却打不开&#xff1b;或者两个容器之间ping不通&#xff0c;curl http://ot…

作者头像 李华
网站建设 2026/10/15 14:53:28

基于WGAN的轴承故障振动信号生成:一维GAN数据增强实战

简介&#xff1a;这份资源围绕一维生成对抗网络&#xff08;GAN-1D&#xff09;展开&#xff0c;采用WGAN结构生成故障轴承振动信号&#xff0c;面向具备Python基础、从事机械故障诊断或数据增强方向的学习者与研究人员。它可用于缓解故障样本稀缺问题&#xff0c;为轴承状态监…

作者头像 李华