Kafka vs RabbitMQ:从消费模型到使用场景的一次讲清

Kafka vs RabbitMQ:从消费模型到使用场景的一次讲清

很多关于 Kafka 和 RabbitMQ 的文章,问题不在"不对",而在于:

  • 讲得太碎
  • 概念堆叠
  • 看完还是不知道什么时候该用哪个

这篇文章只解决一件事:

在真实系统(尤其是 IM / 事件驱动系统)里,
Kafka 和 RabbitMQ 各自应该放在什么位置。


一、先给结论(整篇文章就围绕这句话展开)

Kafka 适合"记录发生了什么"
RabbitMQ 适合"驱动现在要做什么"

如果你把这句话记住,后面的细节只是解释"为什么"。


二、从"消费模型"入手,而不是功能表

RabbitMQ:任务模型(Task / Job)

RabbitMQ 的世界观非常简单:

一条消息 = 一次要被执行的任务

核心问题只有三个:

  1. 这条任务有没有被执行?
  2. 执行成功还是失败?
  3. 失败要不要再试?

👉 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 批量消费的真实收益是:

  1. 减少 offset commit 的网络 IO
  2. 降低 consumer group 的协调成本
  3. 提升业务处理吞吐(批量写 DB / ES)

关键结论

Kafka 批量消费不是为了少拉数据,
而是为了少 commit。


七、ack / nack / requeue:只属于 RabbitMQ 的语义

RabbitMQ 只认一件事:

这条消息能不能从队列中删除

  • ack:处理成功,删除
  • nack:处理失败
  • requeue:失败后是否重新入队

一个非常重要、经常被忽略的事实:

requeue=true 会把消息放回队列头部(前面),
且不可配置为尾部

这也是 RabbitMQ 容易出现:

  • 失败自旋
  • 队列被毒消息卡死

结论

requeue 是异常兜底语义,

不是业务重试语义。


RabbitMQ 的定位

RabbitMQ 的核心目标是:

把"任务"可靠地交给某个消费者去执行。

它关注的是:

  • 一条消息是否被执行
  • 是否成功、是否失败
  • 失败要不要重试
  • 什么时候可以从队列中删除

这是一个任务分发系统(Work Queue)


Kafka 的定位

Kafka 的核心目标是:

记录"发生了什么",并允许多个系统以自己的节奏消费这些事实。

它关注的是:

  • 事件是否被持久化
  • 是否可回放
  • 多个消费者如何独立推进进度
  • 顺序是否可控

这是一个分布式事件日志(Event Log)

相关推荐
肥肥今天也好看2 小时前
Java 日期格式化陷阱:YYYY vs yyyy 导致的生产事故分析
后端
用户948357016512 小时前
可观测性落地:如何在 Java 项目中统一埋点 Trace ID?(一)
后端
天天摸鱼的java工程师2 小时前
volatile 关键字底层原理:为什么它不能保证原子性?
java·后端
leikooo2 小时前
SpringAI 多轮对话报错 400 Bad Request
后端·ai编程
小杨同学492 小时前
C 语言实战:堆内存存储字符串 + 多种递归方案计算字符串长度
数据库·后端·算法
golang学习记2 小时前
Go 中防止敏感数据意外泄露的几种姿势
后端
czlczl200209252 小时前
Spring Boot 构建 SaaS 多租户架构
spring boot·后端·架构
小码编匠2 小时前
完美替代 Navicat,一款开源免费、集成了 AIGC 能力的多数据库客户端工具!
数据库·后端·aigc
顺流2 小时前
从零实现一个数据结构可视化调试器(一)
后端