主题
Kafka vs RocketMQ
一句话:两者都是「分区日志 + 副本」,差别在存储单元的粒度;选型不是比功能清单,而是看消息形态、Topic 规模、团队运维能力和生态依赖。
适用版本:Kafka 3.9(最后一个支持 ZooKeeper 的版本)/ 4.0(仅 KRaft);RocketMQ 4.9 / 5.3 / 5.5。跨版本结论必须标版本,否则很容易拿 4.x 的印象评价 5.x。
为什么需要
两个系统都能做到「高吞吐、可持久化、多副本」,但它们的存储单元不同,导致同一组需求下的成本结构不同:
- 日志采集:Topic 少、单 Topic 流量大、下游是 Flink/Spark。
- 业务消息:Topic 多、单 Topic 流量小、需要延迟/事务/过滤/死信。
把这两类负载放到同一个系统上,通常不是不能跑,而是某一侧的运维成本会被放大。选型要回答的是「哪一侧的成本你更愿意承担」。
核心机制
存储模型:Partition 日志 vs 统一 CommitLog
Kafka:每个 Partition 是一条独立的日志目录,包含多个 Segment(.log、.index、.timeindex)。Partition 既是并行单位,也是副本单位;Leader 负责读写,Follower 拉取。
RocketMQ:所有 Topic 的消息写同一份 CommitLog,每个 Queue 只有一份 20 字节条目的 ConsumeQueue 索引;Queue 是逻辑并行单位,副本单位是 Broker 上的 CommitLog 文件。
由此产生的差异:
| 维度 | Kafka | RocketMQ |
|---|---|---|
| 单 Topic 吞吐 | 高,Partition 并行 + sendfile | 高,CommitLog 顺序写 |
| Topic/Partition 数量大 | 文件与元数据压力大,故障恢复慢 | 统一日志,Topic 数量压力小 |
| 读路径 | 直接按 Partition offset 读日志 | 先读 ConsumeQueue 再读 CommitLog |
| 零拷贝 | 消费转发可用 sendfile,拷贝更少 | 写入用 mmap,读取仍经 PageCache |
| 单分区故障恢复 | 以 Partition 为单位 | 以 Broker 的 CommitLog 为单位 |
RocketMQ 的统一 CommitLog 不是「免费」的:每个 Queue 仍有 ConsumeQueue 文件,万级 Topic × 每 Topic 多 Queue 依然是大量小文件,需要调大 PageCache 和文件句柄。它解决的是「每个 Topic 一套独立日志」的问题,不是「无限 Topic」。
副本与选主
| 维度 | Kafka | RocketMQ |
|---|---|---|
| 副本集合 | ISR(Leader 维护的同步副本集合) | 经典主从:固定 Master/Slave;DLedger:Raft 多数派;5.x:Controller 的 SyncStateSet |
| 写入确认 | acks=all 等 ISR 全部写入 | SYNC_MASTER 等 Slave 确认;DLedger 等多数派 |
| 选主 | KRaft Controller(4.0 唯一模式) | 4.5+ DLedger 自动选主;5.x Controller 自动选主 |
| 已提交消息会丢吗 | acks=all + min.insync.replicas>=2 + 不开 unclean 时不丢 | 同步复制 / 多数派确认后不丢 |
Kafka 的 ISR 不是「最终一致」:它是 Leader 认可的法定确认集合,acks=all 下写入要等 ISR 全员。ISR 可以缩到只剩 Leader,这时 acks=all 等价于 acks=1,所以必须配 min.insync.replicas 和 unclean.leader.election.enable=false。
能力差异(按版本)
| 能力 | Kafka 3.9 / 4.0 | RocketMQ 4.9 | RocketMQ 5.x |
|---|---|---|---|
| 延迟消息 | 无 Topic 级原生延迟,需外部调度或应用层实现 | 18 个固定级别 | Timer 时间轮,任意时间点,受 timerMaxDelaySec 上限约束 |
| 事务 | 事务 API,支持 Kafka 读写链路内的 EOS(read_committed) | 半消息 + 回查 | 半消息 + 回查 |
| 顺序 | Partition 内有序 | Queue 内有序 | Queue / LiteTopic 内有序 |
| Broker 端过滤 | 无 Tag/SQL 过滤,消费端自行过滤 | Tag / SQL92 | Tag / SQL92 |
| 死信队列 | 无内置 DLQ,需应用实现 | 内置 %DLQ% | 内置 %DLQ% |
| 消息轨迹 | 无内置 | 可开 traceTopicEnable | 可开,另有 OpenTelemetry 接入 |
| 多语言接入 | 原生协议生态广 | Remoting(Java 为主) | Remoting + gRPC/HTTP Proxy,另有 Pop 消费 |
| 超大规模会话通道 | 需大量 Topic/Partition | 不支持 | 5.5 LiteTopic |
事务消息不是 RocketMQ 独有:Kafka 有事务 API,Pulsar、RabbitMQ、QMQ 也有各自的实现。准确说法是「RocketMQ 的半消息 + 回查模型适合业务侧本地事务与消息发送的最终一致」,而不是把它说成独有能力。
运维成本
- Kafka:3.9 之前要维护 ZooKeeper 或 KRaft Controller;4.0 只剩 KRaft,元数据在内部日志里。分区重分配、副本迁移、Controller 选举都有成熟工具,但参数多,调优门槛高。
- RocketMQ:NameServer 极简,Broker 参数相对少;5.x 多了 Proxy、Controller 等组件,部署形态更丰富,也意味着更多选择。DLedger / Controller 的引入提高了高可用能力,同时增加了节点数和运维面。
- 托管服务:云上的 Kafka/RocketMQ 都会隐藏底层差异,选型时要看具体产品的版本、配额和限制,不能直接套开源结论。
最小上手
选型前先做一次 10 分钟的现状盘点,而不是先跑 benchmark:
bash
# Kafka:Topic 数、Partition 数、ISR 是否完整、消费积压
bin/kafka-topics.sh --bootstrap-server broker:9092 --list | wc -l
bin/kafka-topics.sh --bootstrap-server broker:9092 --describe | head -50
bin/kafka-consumer-groups.sh --bootstrap-server broker:9092 --describe --group g1
# RocketMQ:Topic 数、队列分布、消费积压
sh bin/mqadmin topicList -n namesrv:9876 | wc -l
sh bin/mqadmin clusterList -n namesrv:9876
sh bin/mqadmin consumerProgress -n namesrv:9876 -g g1需要实测时,用各自的压测工具、自己的消息大小和副本配置:
bash
# Kafka 3.9/4.0
bin/kafka-producer-perf-test.sh --topic bench --num-records 1000000 \
--record-size 1024 --throughput -1 --producer-props \
bootstrap.servers=broker:9092 acks=all
# RocketMQ 发行包自带 example(类路径以版本为准)
sh bin/tools.sh org.apache.rocketmq.example.benchmark.Producer namesrv:9876判断依据:
- Topic/Partition 总数超过单集群的舒适区,优先 RocketMQ。
- 单 Topic 需要极高吞吐、下游是流计算生态,优先 Kafka。
- 需要延迟、事务、Tag 过滤、DLQ 且不想自建,优先 RocketMQ 5.x。
- 团队已有成熟 Kafka 平台和监控,迁移成本要计入选型。
生产动作
- 按「消息形态」而不是「公司用什么」选型。业务消息和日志管道可以用两套集群,没必要强行统一。
- 把 Topic/Partition 数量作为一级容量指标。Kafka 扩 Partition 容易,但元数据、选举、恢复时间都会变差;RocketMQ 建 Topic 容易,但 Queue 文件、PageCache 和文件句柄仍要算。
- 压测必须带副本和刷盘配置。单副本、异步刷盘的吞吐数字不能用于生产容量规划。
- 迁移用双写/双读过渡,不要一次性切。双写要有幂等和对账;切换前用时间位点对齐消费进度。
- 明确版本边界:Kafka 4.0 没有 ZooKeeper 模式;RocketMQ 5.x 的 Timer、Proxy、Controller、LiteTopic 在 4.9 都不存在。
边界
- 没有通用赢家。日志/流计算选 Kafka 更顺,业务消息/多 Topic/延迟事务选 RocketMQ 更省事,这是经验判断,不是定律。
- 「Kafka 只能做日志」已经过时。Kafka 有事务、 compaction、KRaft,也能做业务消息;只是延迟、过滤、DLQ 需要自建。
- 「RocketMQ 万级 Topic 无压力」要加限定。它不受「每 Topic 一套日志」的限制,但仍受 Queue 文件数、PageCache、文件句柄和 NameServer 路由大小的约束。
- 不要把单个项目的选型表当成通用结论。项目里的选择受团队栈、历史包袱、云产品配额影响,换一个组织未必成立。
- 不要用 4.x 的印象评价 5.x。5.x 的 Controller、Proxy、Timer、LiteTopic 改变了高可用、接入和延迟能力的边界。
讲清楚
Kafka 和 RocketMQ 都是分区日志加副本,真正的差别在存储单元。Kafka 一个 Partition 一套日志文件,Partition 既是并行单位也是副本单位;RocketMQ 所有 Topic 共用一份 CommitLog,每个 Queue 只有一份 20 字节的索引。前者适合 Topic 少、单 Topic 流量大的场景,后者适合 Topic 多、每个 Topic 流量不大的业务消息。
副本和选主也不一样。Kafka 用 ISR,Leader 等 ISR 全员确认,配好
acks=all、min.insync.replicas和不选脏主,已提交消息不会丢;它不是「最终一致」。RocketMQ 走过了经典主从、DLedger、Controller 三代,4.5 之后就能自动选主,5.x 的 Controller 把选主独立出来。能力上要按版本说:Kafka 4.0 只支持 KRaft,没有原生延迟 Topic;RocketMQ 4.x 是 18 级延迟,5.x 用 Timer 支持任意时间点,还有 Proxy、Pop、LiteTopic。选型的顺序是:先数 Topic 和 Partition,再看单 Topic 吞吐,再看延迟/事务/过滤/死信是不是硬需求,最后算团队运维成本。只报「哪个性能高」说明不了问题。