news 2026/10/28 2:02:55

面试官:RocketMQ 长轮询是怎么实现的?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
面试官:RocketMQ 长轮询是怎么实现的?

我们知道,消息队列消费端获取消息的方式包括推模式和拉模式,RocketMQ 并没有实现推模式,RocketMQ 的推模式本质上也是拉模式。他们在实现上有下面的不同:

  • 拉模式需要开发在代码里调用拉取消息的方法,拉取到消息后直接进行消息处理;

  • 推模式是消费者客户端初始化时利用重平衡线程去拉取消息,拉取消息的方法会注册回调函数,拉取到消息后,由回调函数触发监听器(定义处理逻辑)进行消息处理。

RocketMQ 为了提供拉取消息的效率,采用了长轮询机制,避免消费端无效的轮询请求。当消费者发送长轮询请求后,如果 Broker 上没有新消息,则不会立刻返回,而是挂起请求,等待新消息到来或者请求超时。

今天来聊一聊 RocketMQ 的长轮询是怎么实现的。

1 长轮询

长轮询的流程如下图:

客户端建立连接后,发送消息拉取请求,如果服务端有新消息,则返回消息。如果服务端没有新消息,则挂起连接,等待新消息到来后给客户端返回。客户端如果连接超时,则断开连接。

2 RocketMQ 实现

2.1 消费端

RocketMQ 消费端长轮询有 2 个超时设置:

  • brokerSuspendMaxTimeMillis:长轮询,Consumer 拉消息请求在 Broker 挂起超过这个时间,就会给消费端返回响应,无论有没有新消息,单位毫秒。这个参数消费端发送拉取请求时会发给 Broker,Broker 用来判断这个长连接是否超时。

  • consumerTimeoutMillisWhenSuspend:消费端发送拉取请求的超时时间,这个时间要大于 brokerSuspendMaxTimeMillis,客户端初始化时会有校验。

注意,这 2 个超时时间官方都不推荐修改。

if (this.defaultLitePullConsumer.getConsumerTimeoutMillisWhenSuspend() < this.defaultLitePullConsumer.getBrokerSuspendMaxTimeMillis()) { throw new MQClientException( "Long polling mode, the consumer consumerTimeoutMillisWhenSuspend must greater than brokerSuspendMaxTimeMillis" + FAQUrl.suggestTodo(FAQUrl.CLIENT_PARAMETER_CHECK_URL), null); }

2.2 Broker

RocketMQ 在 Broker 端通过设置 longPollingEnable 来开启长轮询,默认是开启。

Broker 长轮询挂起时间使用 suspendTimeoutMillis 来进行控制,前面提到过,这个时间由消费者发送的 brokerSuspendMaxTimeMillis 参数来赋值。

2.2.1 挂起消息

Broker 收到客户端拉取消息请求后,如果没有新消息,则将请求挂起,也就是将请求放到 pullRequestTable。

//PullMessageProcessor#processRequest case ResponseCode.PULL_NOT_FOUND: if (brokerAllowSuspend && hasSuspendFlag) { //suspendTimeoutMillisLong 这个参数就是消费端发来的 consumerTimeoutMillisWhenSuspend long pollingTimeMills = suspendTimeoutMillisLong; if (!this.brokerController.getBrokerConfig().isLongPollingEnable()) { pollingTimeMills = this.brokerController.getBrokerConfig().getShortPollingTimeMills(); } String topic = requestHeader.getTopic(); long offset = requestHeader.getQueueOffset(); int queueId = requestHeader.getQueueId(); PullRequest pullRequest = new PullRequest(request, channel, pollingTimeMills, this.brokerController.getMessageStore().now(), offset, subscriptionData, messageFilter); //这里挂起消息 this.brokerController.getPullRequestHoldService().suspendPullRequest(topic, queueId, pullRequest); response = null; break; }

上面的 suspendPullRequest 调用了 PullRequestHoldService#suspendPullRequest,将请求保存在 pullRequestTable。

2.2.2 处理挂起

消息挂起后,后面怎么恢复呢?这里总需要一个线程去循环处理挂起的消息,这个处理逻辑也在 PullRequestHoldService,看下面代码:

public void run() { log.info("{} service started", this.getServiceName()); while (!this.isStopped()) { try { //长轮询模式,等待 5s 后处理 if (this.brokerController.getBrokerConfig().isLongPollingEnable()) { this.waitForRunning(5 * 1000); } //... //这里处理被挂起的请求 this.checkHoldRequest(); } catch (Throwable e) { log.warn(this.getServiceName() + " service has exception. ", e); } }//... }

处理请求的逻辑参考下面代码:

protected void checkHoldRequest() { for (String key : this.pullRequestTable.keySet()) { String[] kArray = key.split(TOPIC_QUEUEID_SEPARATOR); if (2 == kArray.length) { String topic = kArray[0]; int queueId = Integer.parseInt(kArray[1]); finallong offset = this.brokerController.getMessageStore().getMaxOffsetInQueue(topic, queueId); try { this.notifyMessageArriving(topic, queueId, offset); } catch (Throwable e) { log.error("check hold request failed. topic={}, queueId={}", topic, queueId, e); } } } }

notifyMessageArriving 方法逻辑如下:

  1. 如果当前请求有新消息到来,则给消费者返回响应;

  2. 如果当前请求没有新消息,但是挂起请求已经超时,则给消费者返回响应;

  3. 否则, 继续挂起,等待 5s 后重复执行上面逻辑。

3 总结

长轮询可以降低无效的轮询请求,提升请求效率。RocketMQ 消费者长轮询支持配置,当消息量不太大,消费者没有必要频繁地请求,这时可以设置成长轮询机制。需要注意的是,消费端设置的请求超时时间必须大于 Broker 轮询时间。

2026年最新版百万八股面试宝典《Java》《大模型》《大并发》《大数据》

本题库由资深讲师联合大厂面试官精心打造,专为高级IT岗位设计!!!

【220万字八股文面试宝典(领取)】

  • 面试突击体系相关
  • Java企业架构体系相关
  • AI大模型相关
  • HR 面试软技能
  • 设计模式相关
  • 并发编程相关
  • 网络IO与Netty相关
  • 互联网三高项目相关
  • 亿级流量多级缓存相关
  • 数据结构算法相关
  • 分布式相关
  • 分布式锁相关
  • 分布式ID相关
  • 核心源码相关
  • 大厂线上故障分析相关
  • Docker相关
  • Dubbo相关
  • ElasticSearch相关
  • GoLang相关
  • Java基础核心
  • JVM核心相关
  • JVM调优底层相关
  • Kafka相关
  • Kubernetes相关
  • Linux相关
  • MongoDB相关
  • MQ相关
  • MySQL相关
  • MyBatis相关
  • MyBatisPlus相关
  • Postgresql相关
  • RabbitMQ相关
  • RocketMQ相关
  • Redis相关
  • ShardingSphere相关
  • Shiro相关
  • SkyWalking相关
  • Solr相关
  • Spring 相关
  • SpringBoot相关
  • SpringCloud相关
  • SpringMVC源码相关
  • SpringSecurity相关
  • Spring WebFlux相关
  • 领域驱动设计(DDD)相关
  • 任务调度Airflow相关
  • Zookeeper相关
  • HDFS面试题
  • MapReduce面试题
  • Yarn面试题
  • Hive相关
  • SQL面试题相关
  • Scala面试题
  • Spark面试题
  • Flink相关
  • Doris相关
  • Tomcat源码相关
  • 网络安全相关
  • 运维/云原生相关
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/28 2:02:49

Sysplorer 调用外部 C++ 动态库(DLL)完整指南

本指南总结了在 Sysplorer 中调用外部 C DLL 的完整流程、关键配置与常见排错方法&#xff0c;适用于 C 与 Modelica 的混合编程场景。 一、核心成功公式 正确的 C 导出代码一致的工具链&#xff08;MSVC 64 位&#xff09;准确的库路径成功调用二、环境要求项目要求说明操作系…

作者头像 李华
网站建设 2026/10/28 2:02:30

小卫星光照模拟与整星热真空试验:辐照度之外的差异

卫星进入轨道后&#xff0c;持续受到太阳辐照、真空和周期性温度变化的共同影响&#xff0c;这些环境因素会改变航天器的热平衡状态&#xff0c;也可能影响太阳能电池阵列、天线及星载电子设备的工作性能。由于在轨条件难以直接重复&#xff0c;卫星热真空试验系统需要在地面建…

作者头像 李华
网站建设 2026/10/28 2:01:39

有什么持续监控企业风险的工具

一、监管新规落地&#xff0c;供应链风险监控从 “可选项” 变为 “必答题”2026 年 4 月&#xff0c;《国务院关于产业链供应链安全的规定》&#xff08;国令第 834 号&#xff09;正式施行&#xff0c;其中明确提出国家建立健全关键领域产业链供应链安全风险监测预警制度&…

作者头像 李华
网站建设 2026/10/28 2:01:24

ShopXO 电商系统全维度测试报告:功能与自动化双轨验证

摘要&#xff1a;本文以开源电商系统 ShopXO 为被测对象&#xff0c;围绕功能测试、Selenium UI 自动化测试与 JMeter 性能测试三条主线展开&#xff0c;完整记录测试目标、用例设计、工程结构、执行结果与瓶颈分析&#xff0c;并给出可落地的优化建议与实战 tips。项目名称Sho…

作者头像 李华
网站建设 2026/10/28 2:00:48

Oracle 项目实战:业务场景篇——单据编号、分区归档、报表秒出、闪回救援与数据迁移【物化视图、VPD、数据泵、DBMS_SCHEDULER】

✍️ 作者:王文峰(外号:神秘小峯 / 山峯)|中国国学、传统文化与代码爱好者的程序人生,期待你的关注和支持! Oracle 项目实战:业务场景篇——7 个真实场景与解法 一、场景总览:业务话术 → Oracle 解法 二、场景 1:高并发开单——单据编号怎么生成 三、场景 2:单据表…

作者头像 李华
网站建设 2026/10/28 2:00:46

DeepSeek API 报 401、402、429:别把所有错误都当余额不足

API 调用失败&#xff0c;先看 HTTP 状态码和响应里的错误信息。401、402、429 分别指向鉴权、余额和请求速率问题&#xff0c;处理方向完全不同。下面按 DeepSeek 官方直连 API 说明排查&#xff1b;经过第三方网关时&#xff0c;还要确认错误来自网关还是上游&#xff0c;不能…

作者头像 李华