Kafka vs RabbitMQ:从消费模型到使用场景的一次讲清
很多关于 Kafka 和 RabbitMQ 的文章,问题不在"不对",而在于:
- 讲得太碎
- 概念堆叠
- 看完还是不知道什么时候该用哪个
这篇文章只解决一件事:
在真实系统(尤其是 IM / 事件驱动系统)里,
Kafka 和 RabbitMQ 各自应该放在什么位置。
一、先给结论(整篇文章就围绕这句话展开)
Kafka 适合"记录发生了什么"
RabbitMQ 适合"驱动现在要做什么"
如果你把这句话记住,后面的细节只是解释"为什么"。
二、从"消费模型"入手,而不是功能表
RabbitMQ:任务模型(Task / Job)
RabbitMQ 的世界观非常简单:
一条消息 = 一次要被执行的任务
核心问题只有三个:
- 这条任务有没有被执行?
- 执行成功还是失败?
- 失败要不要再试?
👉 RabbitMQ 关心的是"执行结果"
Kafka:事件模型(Event / Fact)
Kafka 的世界观完全不同:
一条消息 = 已经发生的事实
Kafka 不关心:
- 你有没有处理完
- 你处理得快不快
它只关心:
- 事件是否被持久化
- 顺序是否正确
👉 Kafka 关心的是"事件时间线"
三、Push vs Pull 是一切差异的根源
RabbitMQ 是 Push
- consumer 注册后
- broker 主动推消息
- prefetch 只是限制"最多能推多少条未 ack 的消息"
重要结论:
prefetch 不是顺序机制,只是并发/流量控制
Kafka 是 Pull
- consumer 主动拉数据
- broker 一次返回一批连续 offset 的数据
- consumer 决定什么时候处理、什么时候 commit
重要结论:
Kafka 在网络层几乎永远是"批量拉取",
你代码里的一条一条 Consume,大多只是从内存里读
四、顺序问题:为什么 RabbitMQ 很难,Kafka 很自然
RabbitMQ 的顺序能力
RabbitMQ 只有一种可靠的顺序方式:
ini
一个 queue
一个 consumer
prefetch = 1
代价:
- 串行
- 吞吐极低
- 无法横向扩展
一旦:
- 多 consumer
- 或 prefetch > 1
- 或 requeue
👉 顺序立刻失效
结论:
RabbitMQ 的顺序是"副作用",不是设计目标。
Kafka 的顺序能力
Kafka 的顺序来自 partition:
- partition 是顺序日志
- offset 严格递增
- 一个 partition 在一个 consumer group 内只会被一个 consumer 消费
你通过 key 定义顺序边界:
ini
key = userId / orderId / conversationId
得到的是:
- 同一 key 严格有序
- 不同 key 高度并行
结论:
Kafka 的顺序是"结构性能力"。
五、Kafka 的顺序会被网络打乱吗?
不会。
原因很简单:
- broker 返回的数据已经按 offset 排好
- consumer 只按 offset 顺序读取
- 网络快慢只影响"什么时候到",不影响"顺序是什么"
真正会打乱顺序的只有一种情况:
你在 consumer 里并发处理同一个 partition 的消息
六、批量消费到底在解决什么问题?
RabbitMQ 的"批量"
RabbitMQ 没有真正的 batch 消费:
- prefetch = N
- 只是允许同时推 N 条未 ack 的消息
👉 解决的是:并发和流量控制
Kafka 的"批量"
Kafka 的 batch 是消费端行为:
-
broker 本来就批量返回
-
consumer 在内存里:
- 读 N 条
- 一起处理
- 一次 commit
Kafka 批量消费的真实收益是:
- 减少 offset commit 的网络 IO
- 降低 consumer group 的协调成本
- 提升业务处理吞吐(批量写 DB / ES)
关键结论:
Kafka 批量消费不是为了少拉数据,
而是为了少 commit。
七、ack / nack / requeue:只属于 RabbitMQ 的语义
RabbitMQ 只认一件事:
这条消息能不能从队列中删除
- ack:处理成功,删除
- nack:处理失败
- requeue:失败后是否重新入队
一个非常重要、经常被忽略的事实:
requeue=true 会把消息放回队列头部(前面),
且不可配置为尾部
这也是 RabbitMQ 容易出现:
- 失败自旋
- 队列被毒消息卡死
结论:
requeue 是异常兜底语义,
不是业务重试语义。
RabbitMQ 的定位
RabbitMQ 的核心目标是:
把"任务"可靠地交给某个消费者去执行。
它关注的是:
- 一条消息是否被执行
- 是否成功、是否失败
- 失败要不要重试
- 什么时候可以从队列中删除
这是一个任务分发系统(Work Queue) 。
Kafka 的定位
Kafka 的核心目标是:
记录"发生了什么",并允许多个系统以自己的节奏消费这些事实。
它关注的是:
- 事件是否被持久化
- 是否可回放
- 多个消费者如何独立推进进度
- 顺序是否可控
这是一个分布式事件日志(Event Log) 。