RocketMQ 与 Kafka 长轮询详解

RocketMQ 与 Kafka 长轮询详解

一、背景

Consumer 消费消息有两种基本模式:

模式 说明 问题
Push Broker 主动推送消息给 Consumer Consumer 可能来不及处理,造成积压
Pull Consumer 主动向 Broker 拉取消息 频繁拉取浪费资源;消息到达慢导致延迟

长轮询 是对 Pull 模式的优化:Consumer 发起请求后,若暂无消息,Broker 不立即返回,而是挂起请求,等到有新消息或超时后再响应。既避免了频繁空轮询,又保证了消息的实时性。


二、RocketMQ 长轮询

2.1 整体机制

RocketMQ 本质是 Pull 模式,通过长轮询模拟 Push 的实时感。

复制代码
Consumer                     Broker
   │                            │
   │  Pull 请求(带超时时间)    │
   │ ─────────────────────────> │
   │                            │ 有消息?
   │                            ├── YES → 立即返回消息
   │                            │
   │                            └── NO  → 挂起请求
   │                                      进入 PullRequestHoldService
   │                                      等待新消息到达 or 超时
   │                                          │
   │                                  新消息写入 CommitLog
   │                                          │
   │ <─────────────────────────  唤醒挂起请求,立即返回消息
   │                            │
   │  立即发起下一次 Pull        │
   │ ─────────────────────────> │

2.2 核心组件

复制代码
PullMessageProcessor          # 处理 Pull 请求的入口
  ↓(无消息时)
PullRequestHoldService        # 管理挂起请求的后台线程
  ├── 每 5 秒定时轮询(短轮询兜底,防止消息遗漏)
  └── 被 ReputMessageService 实时唤醒

ReputMessageService           # 监听 CommitLog 写入
  └── 新消息写入后调用 notifyMessageArriving()
        └── 唤醒对应 Topic/Queue 的挂起请求

2.3 挂起超时时间

配置 挂起时长 说明
longPollingEnable=true(默认) 30 秒 长轮询,实时性强
longPollingEnable=false 1 秒 短轮询,兜底方案

2.4 唤醒时机

  1. 实时唤醒 :新消息写入 CommitLog → ReputMessageServicenotifyMessageArriving() → 立即唤醒
  2. 超时唤醒PullRequestHoldService 定时线程每 5 秒扫描一次,超过挂起时长则强制返回

2.5 关键特点

  • 消息级别触发:一条新消息写入即可唤醒,延迟极低(毫秒级)
  • 设计目标:低延迟,尽快将消息送达 Consumer
  • 适合场景:对消息实时性要求高的业务(如订单、支付通知)

三、Kafka 长轮询

3.1 整体机制

Kafka Consumer 调用 poll(timeout) 发起 Fetch 请求,Broker 端通过 DelayedFetch 实现挂起等待。

复制代码
Consumer                     Kafka Broker
   │                            │
   │  Fetch 请求                │
   │  fetch.min.bytes=1MB       │
   │  fetch.max.wait.ms=500ms   │
   │ ─────────────────────────> │
   │                            │ 数据量 >= fetch.min.bytes?
   │                            ├── YES → 立即返回
   │                            │
   │                            └── NO  → 创建 DelayedFetch
   │                                      放入 DelayedOperationPurgatory
   │                                      等待触发条件:
   │                                      ① 数据量 >= fetch.min.bytes
   │                                      ② 等待时间 >= fetch.max.wait.ms
   │                                      满足其一则返回
   │ <─────────────────────────  返回数据(可能是空或少量消息)

3.2 核心组件

复制代码
KafkaApis                         # 处理 Fetch 请求入口
  ↓(数据不足时)
DelayedFetch                      # 延迟 Fetch 操作对象
  └── 放入 DelayedOperationPurgatory(炼狱)
          ├── 新消息写入 Partition → tryComplete() → 检查是否满足条件
          └── fetch.max.wait.ms 超时 → onExpiration() → 强制返回

DelayedOperationPurgatory(炼狱) 是 Kafka 管理所有延迟操作的核心组件,长轮询、延迟生产(acks=-1)等都由它统一管理。

3.3 核心配置参数

Consumer 端:

properties 复制代码
# 每次 Fetch 最少返回的数据量(默认 1 字节,即有消息就返回)
fetch.min.bytes=1

# Broker 最长等待时间(默认 500ms)
fetch.max.wait.ms=500

# 每次 poll 最多拉取的消息条数
max.poll.records=500

# Consumer 两次 poll 的最长间隔(超过则认为 Consumer 宕机)
max.poll.interval.ms=300000

Broker 端(副本同步):

properties 复制代码
# 副本 Fetch 最小字节数
replica.fetch.min.bytes=1

# 副本 Fetch 最长等待时间
replica.fetch.wait.max.ms=500

3.4 批量优化场景

通过调大 fetch.min.bytes,可以实现攒批效果:

properties 复制代码
# 至少积累 1MB 数据再返回,减少网络交互次数,提升吞吐量
fetch.min.bytes=1048576
fetch.max.wait.ms=1000

3.5 关键特点

  • 数据量阈值控制 :通过 fetch.min.bytes 攒批,减少网络交互
  • 设计目标:高吞吐,批量拉取摊薄网络开销
  • 适合场景:日志采集、大数据流处理等吞吐量优先的业务

四、两者对比

维度 RocketMQ Kafka
消费模型 Pull 模拟 Push 纯 Pull
挂起组件 PullRequestHoldService DelayedOperationPurgatory
唤醒粒度 消息级别(一条消息即唤醒) 数据量阈值(fetch.min.bytes
默认等待超时 30 秒 500ms
最小数据量控制 fetch.min.bytes(可配置)
实时性 极高(毫秒级) fetch.max.wait.ms 影响
吞吐量 中等 高(批量设计)
设计目标 低延迟 高吞吐
适用场景 订单、支付、实时通知 日志、埋点、大数据流

五、关键区别深度分析

5.1 触发粒度不同

复制代码
RocketMQ:消息级别触发
  一条消息写入 CommitLog → 立即唤醒挂起的 Consumer
  优势:延迟极低
  劣势:高消息频率下,唤醒过于频繁

Kafka:数据量阈值触发
  积累 fetch.min.bytes 数据 → 才返回给 Consumer
  优势:批量传输,网络效率高
  劣势:低流量时可能等到 fetch.max.wait.ms 超时才返回

5.2 设计目标不同

复制代码
RocketMQ 长轮询 → 追求低延迟
  消息产生 → 毫秒内送达 Consumer

Kafka 长轮询 → 追求高吞吐
  通过 fetch.min.bytes 攒批 → 单次网络传输携带更多数据

5.3 超时策略不同

复制代码
RocketMQ:30s 长超时
  维持长连接,减少重连开销
  超时后 Consumer 立即重新发起 Pull

Kafka:500ms 短超时(默认)
  快速返回空结果,由 Consumer poll() 循环控制节奏
  可调大以减少空轮询次数

六、总结

RocketMQ Kafka
一句话概括 用长轮询模拟 Push,追求实时 用长轮询攒批拉取,追求吞吐
核心参数 longPollingEnable、挂起 30s fetch.min.bytesfetch.max.wait.ms
选型建议 业务消息、实时性优先 数据流、吞吐量优先
相关推荐
DBA大董2 小时前
TDengine3.0 DBA常用的运维命令和SQL2
运维·数据库·时序数据库·dba·tdengine
ManageEngineITSM2 小时前
什么是CMDB?配置管理数据库的定义、作用与建设方法一文讲清
大数据·数据库·人工智能·资产管理·变更管理
IvorySQL3 小时前
PostgreSQL 日报|PG19 外键快速路径隐患已修复(8 月 23 日)
数据库·postgresql
Elastic 中国社区官方博客3 小时前
OpenTelemetry Java 扩展:无需分叉 agent 即可自定义追踪
java·大数据·运维·开发语言·数据库·人工智能·elasticsearch
01传说3 小时前
redis开机自启脚本
数据库·redis·缓存
这个DBA有点耶3 小时前
数据库运维的“自动驾驶”:KES-Operator如何把DBA经验编码为软件
数据库·dba·自动化运维
动力 continue4 小时前
MySQL 基础篇 · SELECT 查询大
数据库·sql·mysql·select
程序员-Benothing4 小时前
MySQL 索引下推是什么?——深入理解 ICP 原理与实践
android·数据库·mysql
这个DBA有点耶4 小时前
MySQL主从延迟的“最后一公里”:如何把延迟压到极限
数据库·程序员·架构