文章目录
- 前言
-
- [一、先理解 RabbitMQ、RocketMQ、Kafka 的定位](#一、先理解 RabbitMQ、RocketMQ、Kafka 的定位)
-
- [1.1 RabbitMQ:更像一个灵活可靠的业务消息队列](#1.1 RabbitMQ:更像一个灵活可靠的业务消息队列)
- [1.2 RocketMQ:更像为交易型业务准备的消息中间件](#1.2 RocketMQ:更像为交易型业务准备的消息中间件)
- [1.3 Kafka:更像一个高吞吐的事件流平台](#1.3 Kafka:更像一个高吞吐的事件流平台)
- [1.4 三种 MQ 总览表](#1.4 三种 MQ 总览表)
- [二、为什么 RabbitMQ、RocketMQ、Kafka 的定位不一样?](#二、为什么 RabbitMQ、RocketMQ、Kafka 的定位不一样?)
-
- [2.1 RabbitMQ:核心特点是"路由模型强",所以适合业务解耦](#2.1 RabbitMQ:核心特点是“路由模型强”,所以适合业务解耦)
- [2.2 RocketMQ:核心特点是"围绕业务消息治理设计",所以适合交易型业务](#2.2 RocketMQ:核心特点是“围绕业务消息治理设计”,所以适合交易型业务)
- [2.3 Kafka:核心特点是"日志流模型",所以适合事件流平台](#2.3 Kafka:核心特点是“日志流模型”,所以适合事件流平台)
- 三、不同业务场景下怎么选?
-
- [3.1 普通业务异步解耦:RabbitMQ 或 RocketMQ](#3.1 普通业务异步解耦:RabbitMQ 或 RocketMQ)
- [3.2 订单超时关闭:更适合 RocketMQ](#3.2 订单超时关闭:更适合 RocketMQ)
- [3.3 顺序消息:按业务对象选择队列或分区](#3.3 顺序消息:按业务对象选择队列或分区)
- [3.4 秒杀削峰:RocketMQ 或 Kafka,但 MQ 不是万能的](#3.4 秒杀削峰:RocketMQ 或 Kafka,但 MQ 不是万能的)
- [3.5 日志采集和用户行为埋点:更适合 Kafka](#3.5 日志采集和用户行为埋点:更适合 Kafka)
- [3.6 支付成功后的下游通知:RocketMQ 或 RabbitMQ](#3.6 支付成功后的下游通知:RocketMQ 或 RabbitMQ)
- [场景题:你是否对比过 RabbitMQ 与其他 MQ 的区别?](#场景题:你是否对比过 RabbitMQ 与其他 MQ 的区别?)
- 写在文后
🔥 个人主页:铁皮哥(欢迎关注)
📌 作者简介:28届校招生,后端开发/Agent 方向在学
📚 学习内容:Java、Python、计算机视觉、大语言模型、Agent开发
📝 专栏内容:从零开始的Claude Code零代码生活(持续更新中)
✨不只背八股,更想搞懂为什么这样设计
前言
关于三种消息队列 RabbitMQ、RocketMQ和Kafka 如何选择,刚开始学消息队列的时候,我其实也很容易陷入一种误区:把 RabbitMQ、RocketMQ、Kafka 放在一张表里硬背。
比如 RabbitMQ 延迟低、RocketMQ 支持事务消息、Kafka 吞吐量高;再比如谁支持顺序消息,谁适合削峰填谷,谁适合日志采集。
这些内容当然要知道,但如果只停留在这个层面,面试时很容易变成"背八股"。
因为真正做系统设计的时候,面试官通常不会只问:
RabbitMQ、RocketMQ、Kafka 有什么区别?
他更可能换一种问法:
用户注册成功后,要异步发送短信和优惠券,你会怎么设计?
订单 30 分钟未支付自动取消,用什么方案?
秒杀流量突然打上来,MQ 能解决什么问题?
如果要做日志采集和用户行为埋点,为什么很多系统会选择 Kafka?
这时候,如果只是回答"Kafka 吞吐量高,RocketMQ 支持事务消息,RabbitMQ 路由灵活",其实还不够。更好的回答应该是:先看业务场景,再看 MQ 的特性是否匹配。
比如,普通的业务异步解耦,不一定非要追求极高吞吐,重点是消息能不能可靠投递、失败后能不能重试、不同业务服务能不能独立消费。订单、支付、库存这类交易场景,则更关注延时消息、顺序消息、事务消息这些能力。而日志采集、用户行为埋点、实时计算这类数据流场景,才更适合用 Kafka 这种高吞吐、可回放的事件流平台。
MQ 选型不是为了证明哪个中间件最强,而是为了回答一个更实际的问题:
在当前业务场景下,用哪个 MQ 更合适,成本更低,风险更小。
这也是我写这篇文章的目的。
不是为了多背几个概念,而是希望下次再遇到 MQ 相关的系统设计题时,能从"我知道它们的区别",进一步说到"我知道这个场景为什么这么选"。
一、先理解 RabbitMQ、RocketMQ、Kafka 的定位
RabbitMQ、RocketMQ、Kafka 虽然都可以用来传消息,但它们的设计重点并不一样。
1.1 RabbitMQ:更像一个灵活可靠的业务消息队列
RabbitMQ 给我的第一印象是:它更适合做业务系统里的异步解耦和消息通知。
比如一个用户注册成功之后,系统可能要做很多事情:发短信、发邮件、送优惠券、初始化积分账户、通知风控系统等等。
如果这些操作都放在注册接口里同步执行,那接口会变得很重。短信服务慢一点,注册接口就跟着慢;优惠券服务挂了,可能还会影响用户注册主流程。
这时候就可以把注册成功这件事丢到 MQ 里:
text
用户注册成功
↓
发送一条"用户注册成功"的消息
↓
短信服务、优惠券服务、积分服务各自消费
这样一来,注册接口只需要保证核心流程完成,后面的扩展动作交给其他服务慢慢处理。
RabbitMQ 比较适合这种场景。它的优势不在于极限吞吐,而在于消息模型比较清晰,路由能力比较灵活,用起来也相对直观。比如通过交换机和队列,可以比较方便地实现不同消息分发到不同业务服务。
1.2 RocketMQ:更像为交易型业务准备的消息中间件
RocketMQ 给我的感觉和 RabbitMQ 不太一样。
RabbitMQ 更像是一个"灵活的消息投递工具",而 RocketMQ 更像是一个面向复杂业务场景的消息中间件,尤其适合订单、支付、库存这类交易链路。
举个很常见的例子:订单 30 分钟未支付自动取消。
这个需求如果用定时任务去扫表,也不是不能做,但会有一些问题。比如扫描频率怎么定?数据量大了怎么办?订单刚好过期但还没扫到怎么办?
如果用 RocketMQ 的延时消息,思路就会更自然:
text
用户创建订单
↓
发送一条 30 分钟后的延时消息
↓
消费者收到消息后检查订单状态
↓
如果订单仍未支付,就关闭订单并释放库存
这个场景就很贴近 RocketMQ 的定位。
除了延时消息,RocketMQ 在顺序消息、事务消息这些方面也经常和业务场景绑定在一起。比如订单状态流转需要保证顺序,支付成功后要通知下游系统,又要尽量保证本地事务和消息发送之间的一致性,这些都是 Java 后端开发里很常见的问题。
如果你的系统是偏电商、金融、交易链路,或者你希望 MQ 能更好地承接业务语义,那 RocketMQ 通常会比 RabbitMQ、Kafka 更容易讲清楚。
1.3 Kafka:更像一个高吞吐的事件流平台
Kafka 很多人会简单记成一句话:吞吐量高。
这句话没错,但不够准确。
如果只说 Kafka 吞吐量高,很容易把它理解成"性能更强的 MQ"。但实际上,Kafka 的定位更偏向事件流平台,它特别适合日志采集、用户行为埋点、实时计算、数据管道这类场景。
比如一个 App 里有大量用户行为数据:
text
用户点击、浏览、搜索、下单等行为
↓
写入 Kafka
↓
Flink / Spark Streaming 等任务消费
↓
实时大屏、推荐系统、风控系统、数据仓库
这类场景的特点是:消息量很大,数据需要持续写入,后面可能有多个系统反复消费,甚至还需要根据历史消息重新计算。
Kafka 就很适合这种模式。它不是只负责"把消息从 A 发到 B",而是更像一个数据流的中转层。数据写进来以后,可以被不同消费者订阅,也可以在一定时间内保留下来,方便后续回放和处理。
如果业务重点是"交易消息",Kafka 不一定是最顺手的选择;但如果重点是"海量数据流转和实时分析",Kafka 就非常合适。
1.4 三种 MQ 总览表
简单总结一下:
text
RabbitMQ:更适合普通业务异步解耦和灵活路由
RocketMQ:更适合订单、支付、库存等交易型业务消息
Kafka:更适合日志、埋点、实时计算等高吞吐数据流场景
| 对比项 | RabbitMQ | RocketMQ | Kafka |
|---|---|---|---|
| 核心定位 | 业务消息队列 | 交易型消息中间件 | 分布式事件流平台 |
| 典型场景 | 异步解耦、任务通知、灵活路由 | 订单、支付、库存、延时消息、事务消息 | 日志采集、埋点、实时计算、数据管道 |
| 主要优势 | 路由灵活、使用直观、业务解耦方便 | 业务语义强,适合复杂交易链路 | 吞吐高、可回放,适合持续数据流 |
| 关注重点 | 消息怎么投递到不同业务方 | 消息如何支撑业务一致性 | 数据如何高吞吐地持续流转 |
| 更像什么 | 业务事件分发器 | 交易消息协调器 | 数据流管道 |
你这个反馈很对。上一版的问题是:我写了 RocketMQ 能做什么,但没有讲清楚"为什么这些能力会让它更适合交易型业务"。而且像延时消息、顺序消息、事务语义这些能力,其他 MQ 也可能有类似实现,所以不能只靠"功能列表"来证明定位。
下面重新写一版完整第二章,重点改成:
不是简单说某个 MQ 有什么功能,而是讲它的模型、设计取向、能力边界,为什么会影响选型。
二、为什么 RabbitMQ、RocketMQ、Kafka 的定位不一样?
2.1 RabbitMQ:核心特点是"路由模型强",所以适合业务解耦
RabbitMQ 最明显的特点是它的消息路由模型非常灵活。
在 RabbitMQ 里,生产者通常不是直接把消息发到某个队列,而是先发给 Exchange,也就是交换机。然后交换机再根据不同的规则,把消息投递到一个或多个队列中。
这个设计很关键。
因为它让生产者不需要关心消息最终会被哪些消费者处理。生产者只负责表达一件事:
某个业务事件发生了。
至于这条消息要给短信服务、优惠券服务、积分服务,还是风控服务处理,可以通过交换机、队列和绑定关系来决定。
比如用户注册成功之后:
text
用户服务
↓
发送"用户注册成功"消息到 Exchange
↓
Exchange 根据绑定关系分发
↓
短信队列、优惠券队列、积分队列、风控队列
这个模型特别适合业务系统中的"事件分发"。
因为在真实项目里,一个业务动作后面往往会挂很多扩展逻辑。今天用户注册后只需要发短信,明天可能要发优惠券,后天又要接入用户画像系统。如果所有逻辑都写在注册接口里,主流程会越来越重。
但如果用 RabbitMQ,注册服务只需要发出一条事件消息。后面谁要消费,就自己绑定对应队列。
这就是 RabbitMQ 适合业务解耦的原因。
它的优势不是"我也能发消息",而是它的模型天然强调:
消息应该如何被灵活地分发到不同业务方。
这一点和 Kafka、RocketMQ 的侧重点是不一样的。
Kafka 更强调 Topic + Partition 这种日志流模型,适合持续写入和消费数据流;RocketMQ 更强调 Topic + Queue + 消费组这套业务消息模型,适合稳定地承载业务消息流转。但 RabbitMQ 的 Exchange 模型让它在复杂路由上更直观,比如:
text
direct:根据明确的 routing key 投递
fanout:广播给所有绑定队列
topic:根据通配符规则做主题匹配
headers:根据消息头做匹配
这些路由方式决定了 RabbitMQ 在"一个业务事件触发多个系统处理"这类场景里会很顺手。
比如:
text
订单创建成功
↓
库存系统扣减预占库存
积分系统记录待发积分
风控系统检查异常订单
通知系统发送站内信
这些消费者之间互不影响,也不需要订单服务知道它们的存在。
所以 RabbitMQ 的选型逻辑可以这样理解:
如果你的核心诉求是业务系统之间解耦,消息分发规则比较灵活,业务事件后面可能挂多个消费者,那么 RabbitMQ 的 Exchange + Queue 模型会比较自然。
2.2 RocketMQ:核心特点是"围绕业务消息治理设计",所以适合交易型业务
RocketMQ 整体上更偏向业务消息治理。
什么叫业务消息治理?
简单说,就是它关注的不只是"消息能不能发出去",而是更关注:
消息和业务状态之间的关系能不能处理好。
订单系统里的消息,和日志系统里的消息是不一样的。
日志消息丢一小部分,可能影响统计准确性,但通常不会直接导致一笔订单状态错误。
但交易消息如果处理错了,可能就是库存扣错、订单状态错乱、优惠券重复发放、账户流水不一致。
所以交易型业务消息通常有几个特点:
text
它和具体业务对象强绑定,比如订单号、支付单号、用户 ID。
它经常要求同一个业务对象的消息按顺序处理。
它需要比较强的失败重试和消费状态管理。
它经常涉及本地事务和消息发送之间的一致性。
它对消息堆积后的可控性要求比较高。
RocketMQ 的很多设计,刚好是围绕这些问题展开的。
比如 RocketMQ 的 Topic 下面会有多个 MessageQueue。生产者发送消息时,可以根据业务 key 做队列选择,让同一个订单号的消息进入同一个队列。消费者再按队列顺序消费。
这就很适合处理同一个业务对象的状态流转。
比如同一个订单的状态变化:
text
订单创建
↓
订单支付
↓
订单发货
↓
订单完成
这里真正重要的不是"MQ 是否支持顺序消息"这几个字,而是:
RocketMQ 的队列模型比较容易把同一个业务对象的消息固定到同一条有序队列里,从而保证这个业务对象内部的事件顺序。
Kafka 也有 Partition 内有序,也可以通过 key 把同一个订单写到同一个 Partition。
但 Kafka 的强项是大规模事件流和数据处理,它更关心消费者通过 offset 读取日志流。而 RocketMQ 的使用语境更偏业务消息,顺序消息、重试、死信、消费组、消息轨迹、延时消息这些能力,更容易和业务链路结合起来。
再比如事务消息。
RocketMQ 的事务消息不是为了实现强一致的分布式事务,而是为了解决一个非常典型的后端问题:
text
本地事务提交成功了,但消息没发出去怎么办?
消息发出去了,但本地事务失败了怎么办?
在订单支付场景里,这个问题很常见:
text
更新订单状态为"已支付"
↓
发送"支付成功"消息
↓
库存、积分、优惠券等系统消费
如果本地订单状态和消息发送之间没有协调机制,就很容易出现状态不一致。
RocketMQ 的事务消息通过"半消息 + 本地事务执行 + 事务状态回查"的方式,把消息发送和本地事务之间建立了一层协调关系。
RocketMQ 把这类交易系统里高频出现的一致性问题,直接抽象成了 MQ 层面的能力。
这就让它在订单、支付、库存这类场景里更容易落地。
再比如延时消息。
订单超时取消这个场景,其他 MQ 当然也能做。RabbitMQ 可以通过 TTL + 死信队列或插件方式实现,Kafka 也可以通过业务侧延迟调度、时间轮、延迟 topic 等方式实现。
但差别在于:
RocketMQ 把延时消息作为比较直接的业务消息能力来使用,和订单超时、延迟重试这类场景匹配度更高。
对于业务开发来说,这种差别很现实。
有些方案能做,但需要你绕一层。
有些方案是它本来就鼓励你这么用。
选型时就要考虑这个成本。
2.3 Kafka:核心特点是"日志流模型",所以适合事件流平台
Kafka 的定位最容易被简单化。
很多人只记一句:
Kafka 吞吐量高。
这句话没错,但它解释不了 Kafka 为什么适合日志采集、埋点、实时计算。
真正决定 Kafka 定位的,是它的日志流模型。
Kafka 里的消息不是传统意义上"投递给某个消费者后就结束"的任务消息,而是被追加写入到 Topic 的 Partition 里。每个 Partition 都像一条不断增长的日志。
生产者持续往里面写事件。
消费者按照 offset 去读。
消息被读完之后,不会因为某个消费者消费成功就立刻消失,而是会按照保留策略继续保存一段时间。
这个模型和 RabbitMQ、RocketMQ 的业务消息模型有明显区别。
RabbitMQ 更像是"消息来了,我根据路由规则投递给队列,消费者处理任务"。
RocketMQ 更像是"业务消息来了,我要保证它可靠、可控地完成业务流转"。
Kafka 更像是"事件不断写进一条日志流,多个系统可以按照自己的进度读取"。
这个差异决定了 Kafka 特别适合事件流场景。
比如用户行为埋点:
text
用户打开页面
用户点击按钮
用户搜索商品
用户加入购物车
用户提交订单
这些数据有几个特点。
第一,它们是持续产生的,不是一条两条,而是源源不断。
第二,它们通常不只给一个系统用。推荐系统要用,风控系统要用,数据仓库要用,实时大屏也要用。
第三,它们经常需要回放。比如实时计算任务出错了,修复代码之后,可能需要从某个 offset 重新消费历史数据。
Kafka 的模型刚好适合这些需求。
因为 Kafka 的消费者不是从队列里"拿走"消息,而是维护自己的 offset。不同消费组之间互不影响。
也就是说,同一份数据可以被多个系统独立消费:
text
用户行为事件
↓
Kafka Topic
↓
推荐系统消费组
风控系统消费组
数仓同步消费组
实时大屏消费组
推荐系统消费到哪里,不影响风控系统。
风控系统处理慢了,也不影响数仓同步。
如果某个系统需要重跑,还可以调整 offset 重新消费。
这就是 Kafka 适合事件流的核心原因。
它不是单纯"吞吐量高",而是它的模型天然支持:
text
持续写入
顺序追加
数据保留
多消费组独立消费
基于 offset 的回放
这些特点组合在一起,才形成了 Kafka 的事件流定位。
再看日志采集场景,就更明显了。
系统日志、接口调用日志、用户行为日志,本质上都不是传统任务消息。它们更像一条条事件记录。
你不一定要让某个消费者立刻处理完它们。更常见的做法是先把这些事件稳定写入 Kafka,然后由不同系统慢慢消费:
text
业务服务日志
↓
Kafka
↓
Flink 实时计算
Elasticsearch 检索
数据仓库离线分析
监控告警系统
Kafka 在这里承担的角色,不是"把任务派发给某个消费者",而是"把持续产生的数据流稳定地接住,并提供给多个系统使用"。
所以 Kafka 适合事件流平台,是由它的日志模型决定的。
它的高吞吐也不是凭空来的。
顺序追加写、分区并行、批量发送、消费者按 offset 拉取,这些机制一起决定了 Kafka 更适合大规模数据流转。
但也正因为它更像日志流平台,所以如果你拿 Kafka 去做一些强业务语义的消息场景,可能就没那么舒服。
比如复杂路由、订单延时取消、本地事务与消息发送一致性、消费失败后的业务补偿治理,这些不是 Kafka 最核心的表达方式。能做,但通常要依赖业务侧设计更多东西。
所以 Kafka 的选型逻辑可以这样理解:
如果你的核心问题是海量事件如何持续写入、长期保存、被多个系统独立消费,并且支持回放,那么 Kafka 很合适。
如果你的核心问题是业务任务如何灵活路由,或者交易消息如何可靠完成业务流转,Kafka 不一定是最顺手的选择。
三、不同业务场景下怎么选?
前面两章聊了三种 MQ 的定位,也解释了为什么它们会形成这样的定位。
但真正选型的时候,不能只停留在"RabbitMQ 路由灵活、RocketMQ 适合交易、Kafka 适合事件流"这种结论上。因为在真实项目里,问题通常不是摆在纸面上的参数对比,而是一个个具体业务场景。
比如:
text
用户注册后要发短信,用哪个 MQ?
订单 30 分钟未支付自动取消,用哪个 MQ?
秒杀流量突然打上来,MQ 到底能解决什么问题?
日志采集和用户行为埋点,为什么常用 Kafka?
这些问题比单纯问"RabbitMQ、RocketMQ、Kafka 有什么区别"更接近实际开发。
所以这一章就从几个常见场景出发,看看不同 MQ 应该怎么选。
3.1 普通业务异步解耦:RabbitMQ 或 RocketMQ
最常见的 MQ 使用场景,其实不是特别复杂的交易链路,而是普通业务里的异步解耦。
比如用户注册成功后,系统可能要发送短信、发送邮件、发放优惠券、初始化积分账户。下单成功后,可能要通知库存系统、通知积分系统、通知营销系统。
如果这些操作都放在主流程里同步执行,接口会越来越重。
比如注册接口本来只需要创建用户,但后来又加上短信、优惠券、积分、风控,一旦某个下游服务变慢,注册接口也会被拖慢。更严重一点,如果某个非核心服务异常,还可能影响用户注册这个核心流程。
这种场景就很适合用 MQ 拆开:
text
用户注册成功
↓
发送"用户注册成功"消息
↓
短信服务、优惠券服务、积分服务各自消费
主流程只负责完成核心业务,然后发出一条事件消息。后面的服务想消费就消费,不想消费也不影响主流程。
这个场景下,RabbitMQ 和 RocketMQ 都可以选。
如果业务系统规模不算特别大,消息路由规则比较多,比如不同类型的消息要进入不同队列,一个事件要广播给多个业务方,那么 RabbitMQ 会比较顺手。它的 Exchange + Queue 模型很适合这种业务事件分发。
如果公司技术栈本来就偏 RocketMQ,或者后续这个业务可能继续扩展出延时消息、顺序消息、消费重试、死信治理等能力,那直接使用 RocketMQ 也没问题。
3.2 订单超时关闭:更适合 RocketMQ
订单超时关闭是一个非常典型的 Java 后端场景。
用户创建订单后,如果 30 分钟内没有支付,系统需要自动取消订单,并释放库存。
最直观的做法是写一个定时任务,每隔一段时间去数据库扫描未支付订单。
这种方案简单,但问题也比较明显。
如果扫描间隔太短,会给数据库带来压力。
如果扫描间隔太长,订单关闭又不够及时。
订单量大了之后,扫表本身也会变成一个负担。
用 MQ 做的话,思路会更自然:
text
用户创建订单
↓
发送一条 30 分钟后的延时消息
↓
消费者收到消息
↓
查询订单状态
↓
如果仍未支付,则关闭订单并释放库存
这个场景更适合 RocketMQ。
原因不是说只有 RocketMQ 能做延时消息,而是 RocketMQ 的延时消息和业务消息模型更贴近这种交易场景。
RabbitMQ 也可以通过 TTL + 死信队列实现类似效果,但这更像是利用队列过期和死信转发组合出来的方案。能做,但理解成本和维护成本会稍微高一些。
Kafka 也可以通过业务侧延迟调度、延迟 Topic、时间轮等方式实现,但这已经不是 Kafka 最自然的使用方式了。Kafka 更擅长的是持续事件流,而不是订单级别的延迟任务调度。
而 RocketMQ 在订单超时、延迟重试、定时触发这类场景里,用起来会更直接。
不过这里有一个细节要注意:收到延时消息后,不能直接关闭订单。
消费者一定要先查订单状态。
因为用户可能在第 29 分钟已经完成支付,只是延时消息第 30 分钟才被消费。如果消费者不查状态,直接关闭订单,就会把已支付订单误关。
所以正确逻辑应该是:
text
收到订单超时消息
↓
查询订单状态
↓
如果未支付,关闭订单并释放库存
↓
如果已支付,什么都不做
3.3 顺序消息:按业务对象选择队列或分区
顺序消息也是面试里经常会问的点。
比如订单状态流转:
text
订单创建
↓
订单支付
↓
订单发货
↓
订单完成
对于同一个订单来说,这几个事件的处理顺序不能乱。
如果消费者先收到"订单完成",再收到"订单支付",下游系统就会很难处理。
这种场景下,选型时不能只说"哪个 MQ 支持顺序消息",而要先问清楚:你要保证的是全局顺序,还是局部顺序?
全局顺序指的是所有消息都严格按照发送顺序消费。这个要求很重,通常会牺牲并发能力,实际业务中并不常见。
更常见的是局部顺序,也就是同一个业务对象内部有序。
比如同一个订单的消息要有序,但不同订单之间不需要有序。订单 A 和订单 B 谁先处理,并不重要。
这个时候,核心思路就是:
text
把同一个业务 key 的消息发送到同一个队列或分区
比如订单消息可以按 orderId 路由。
同一个 orderId 的消息进入同一个队列或分区,由消费者顺序处理。
不同 orderId 的消息分散到不同队列或分区,提高整体并发。
RocketMQ 很适合这种业务顺序消息场景,因为它的 MessageQueue 模型和业务 key 绑定起来比较自然。Kafka 也能做类似事情,因为 Kafka 的 Partition 内部天然有序,只要同一个 key 写入同一个 Partition,就能保证同一个 key 下的消息顺序。
RabbitMQ 也可以通过单队列、单消费者来保证顺序,但如果要兼顾高并发和局部顺序,设计上会相对别扭一些。
3.4 秒杀削峰:RocketMQ 或 Kafka,但 MQ 不是万能的
秒杀场景也经常和 MQ 一起出现。
很多文章会直接写:
秒杀高并发可以用 MQ 削峰。
这句话没错,但容易让人误解成:只要用了 MQ,秒杀问题就解决了。
实际上,MQ 在秒杀里主要解决的是削峰和异步化,不是解决所有问题。
一个比较典型的秒杀流程可能是这样:
text
用户发起秒杀请求
↓
接口层限流、风控、参数校验
↓
Redis 预扣库存
↓
请求写入 MQ
↓
消费者异步创建订单
↓
订单创建成功后确认库存结果
在这个流程里,MQ 的作用是把瞬间打到订单系统的流量先接住,让后端消费者按照自己的处理能力慢慢消费。
这样可以避免所有请求直接压到数据库上。
但 MQ 不能单独解决超卖问题。
超卖通常要靠 Redis 原子扣减、Lua 脚本、数据库唯一约束、库存流水、幂等处理等机制一起保证。
所以写秒杀场景时,一定要强调:
MQ 负责削峰和异步下单,不负责单独保证库存不超卖。
那秒杀场景该选 RocketMQ 还是 Kafka?
如果是典型电商秒杀,后面要创建订单、扣库存、处理支付链路,我会更偏向 RocketMQ。因为它更贴近业务消息处理,后续的重试、死信、消息轨迹、顺序处理、延时取消订单等能力会更自然。
如果是超大规模的事件接入,比如大量用户行为、点击流、活动曝光日志,需要先接入再做实时计算,那么 Kafka 会更合适。
也就是说:
秒杀交易链路,偏 RocketMQ。
秒杀活动数据流、日志流、行为流,偏 Kafka。
RabbitMQ 也可以用于中小规模秒杀削峰,但如果并发量非常高、消息堆积很大,就要谨慎评估它的吞吐和堆积能力。
3.5 日志采集和用户行为埋点:更适合 Kafka
日志采集、用户行为埋点、实时计算,是 Kafka 最典型的使用场景。
这类数据和订单消息不太一样。
订单消息通常是强业务语义的,比如"订单已支付""库存扣减成功"。每条消息都和具体业务状态强相关,处理错了可能会直接影响业务结果。
但日志和埋点更像持续产生的事件流。
比如:
text
用户打开 App
用户浏览商品
用户点击按钮
用户搜索关键词
用户加入购物车
用户提交订单
这些事件可能会被很多系统使用。
推荐系统要用它分析用户兴趣。
风控系统要用它判断异常行为。
实时大屏要用它展示活动效果。
数据仓库要用它做离线分析。
这时候 Kafka 就很合适。
因为 Kafka 的 Topic + Partition + Offset 模型非常适合这种持续写入、多方消费、可回放的数据流。
text
前端埋点 / 服务日志
↓
Kafka
↓
Flink 实时计算
数据仓库同步
推荐系统
风控系统
实时大屏
每个系统可以用自己的消费组独立消费,不会互相影响。如果某个实时计算任务出错了,也可以调整 offset 重新消费一段历史数据。
这就是 Kafka 在事件流场景里的优势。
如果用 RabbitMQ 做日志采集,也不是完全不行,但它不是围绕大规模日志流和数据回放设计的。
如果用 RocketMQ 做日志流,也能接入数据,但它更强的业务消息治理能力在这个场景下不一定用得上。
3.6 支付成功后的下游通知:RocketMQ 或 RabbitMQ
支付成功后通知下游系统,也是很常见的业务场景。
比如用户支付成功之后,系统可能要做这些事:
text
更新订单状态
↓
通知库存系统扣减库存
通知积分系统增加积分
通知优惠券系统核销优惠券
通知物流系统准备发货
这个场景和用户注册发短信有点像,都是一个业务事件触发多个下游动作。
但支付成功比注册成功更敏感。
因为它涉及订单状态、库存、优惠券、账户流水,下游系统处理失败时要能重试,重复消费时要能幂等,必要时还要有补偿和排查手段。
所以如果是简单的下游通知,RabbitMQ 可以胜任。它的路由模型适合把支付成功事件分发给多个业务服务。
但如果支付链路比较复杂,比如需要事务消息、可靠重试、死信队列、消息轨迹、顺序处理,那 RocketMQ 会更贴近。
这里有一个很重要的工程细节:消费者一定要做幂等。
因为 MQ 通常很难保证消息只被消费一次。实际系统里更常见的是"至少投递一次",也就是消息可能被重复消费。
比如积分服务收到两次"支付成功"消息,如果不做幂等,就可能给用户加两次积分。
所以消费者应该根据业务唯一键做幂等控制,比如 orderId、paymentId、messageId。
场景题:你是否对比过 RabbitMQ 与其他 MQ 的区别?
我对比过 RabbitMQ、RocketMQ 和 Kafka。
RabbitMQ 更偏传统业务消息队列,适合用户注册后发短信、支付成功后通知积分服务这类异步解耦场景。它的路由模型比较灵活,使用成本也相对低。
RocketMQ 更偏交易型业务消息,比较适合订单、支付、库存这类对消息可靠性要求高的场景,尤其是需要延时消息、顺序消息、事务消息时,RocketMQ 会更贴近业务需求。
Kafka 更像分布式事件流平台,适合日志采集、用户行为埋点、实时计算、大数据管道这类对消息可靠性要求低,但对吞吐量要求高、实时性强的场景。
如果是普通业务解耦,可以选 RabbitMQ;如果是电商交易链路,我会更倾向 RocketMQ;如果是日志和数据流处理,我会更倾向 Kafka。同时也要考虑团队已有技术栈和运维成本。
写在文后
期待您的一键三连!如果有什么问题或建议欢迎在评论区交流!