消息队列从入门到跑路,保姆级教程!傻子可懂

你是小阿巴,刚刚为电商系统的双 11 大促开发了秒杀抢购功能。

0 点秒杀开始,每秒上万个用户同时点击抢购按钮,你的数据库瞬间被打垮!

你急得满头大汗,只能找到 "后端之狗" 鱼皮求助:阿巴阿巴......

鱼皮看了看你的代码:用户每次抢购,你的代码都要同步处理校验库存、扣减库存并创建订单等多个操作。同时抢购的用户多了,系统就会压力山大。

你急了:那咋办啊?我总不能拒绝用户吧!

鱼皮嘿嘿一笑:可以用消息队列呀。

你一脸懵:消息队列?那是啥?

⭐️ 推荐观看视频讲解,更通俗易懂:bilibili.com/video/BV12q...

第一阶段:认识消息队列

鱼皮:消息队列(俗称 MQ)就像一个快递驿站。快递员作为 生产者 ,把包裹(消息)放到驿站(消息队列),收件人作为 消费者,自己到驿站去取。

这样一来,快递员放下包裹就能走,不用费时间等你签收(异步)。

你也不用关心是谁送的、不用和快递员见面,有空去驿站取就行(解耦)。

就算双 11 包裹很多,驿站也能暂存起来等消费者慢慢取(削峰)。

这就是消息队列的三大作用:异步、解耦和削峰。

对于你的秒杀抢购系统,现在用户每次抢购都要同步执行各种操作(校验库存、扣减库存、创建订单),全部完成才能返回结果。

如果使用消息队列,用户点击抢购后,系统先做基本的校验并在缓存中预扣库存,确认可以抢购后,把抢购请求(消息)投入消息队列,就可以立刻返回结果了(页面)。

接下来由后台服务从队列中取出消息并处理那些耗时的操作,比如创建订单、在数据库中真正扣减库存。

这就是 异步:用户不用等所有后端操作完成,就能快速得到响应。

而且,抢购服务只管发消息,不用关心是谁来处理库存、谁来创建订单。假如以后要加短信通知、用户行为分析等功能,只需要让新服务也去监听消息队列就行,完全不用修改抢购服务的代码。

这就是 解耦:服务之间不直接依赖,让系统能灵活扩展。

如果同时抢购的用户过多,数据库处理不过来,也可以用消息队列做缓冲。所有的抢购请求先快速存入队列,后台服务可以根据自己的能力从队列中慢慢拉取消息并进行处理。

这就是 削峰:削平流量洪峰,保护后端系统不被压垮。

你恍然大悟:原来如此,消息队列也太强大了吧!俺要学,俺要学!

鱼皮:很有干劲嘛!主流的消息队列实现技术有:

  • RabbitMQ:简单易学、生态活跃,适合中小规模应用
  • Kafka:吞吐量高、延迟极低,适合大数据、日志收集场景
  • RocketMQ:阿里出品、支持事务消息,适合电商金融等对可靠性要求高的场景

你:阿巴阿巴,这么多都要学吗?

鱼皮:新手建议从 RabbitMQ 开始入门,学好一个再学其他的就很简单了。下面我就以 RabbitMQ 为例带你快速掌握消息队列必知必会的技术。

你:期待住了,这不得点赞狠狠支持?!

第二阶段:RabbitMQ 快速上手

鱼皮:首先来安装 RabbitMQ,笨办法是先安装 Erlang 语言环境,再去 官网下载 MQ 的安装包并执行。

但是更建议直接用 Docker 容器技术,快速安装和运行,不用担心版本不兼容。

安装完之后,访问 http://localhost:15672 就可以打开 RabbitMQ 内置的可视化管理界面(默认用户名和密码都是 guest),你可以在这里查看队列的运行情况、手动发送和接收消息。

另外,RabbitMQ 也提供了命令行工具 rabbitmqctl,主要用于运维管理,比如创建用户、查看状态等。

你:那我怎么用代码操作 RabbitMQ 呢?

鱼皮:RabbitMQ 提供了各种编程语言的 SDK 开发包,如果你是 Java 开发者,推荐使用 Spring AMQP

AMQP 是高级消息队列协议(Advanced Message Queuing Protocol)的缩写,是一个开放标准,不绑定特定技术。RabbitMQ 就是基于 AMQP 实现的,所以客户端库叫 Spring AMQP。

只需几行代码,就能创建队列、让生产者发送消息、让消费者接收处理消息:

你:不是吧,这么简单?!

鱼皮:没错,但刚刚我们只是完成了最简单的 1 对 1 发送和接收消息。

实际上 RabbitMQ 有 6 种工作模式,适用于不同的业务场景,这也是消息队列的学习重点。

第三阶段:RabbitMQ 工作模式

简单模式

最简单的是 Simple 模式,一个生产者、一个队列、一个消费者。

就像老板派发任务给员工,队列(Queue) 是存储任务的容器,老板把任务放进去,员工从里面取出来完成。

工作队列模式

鱼皮:如果有很多任务要处理,一个员工忙不过来怎么办?

你:多找几个员工帮忙?

鱼皮:没错,这就是 Work Queue 工作队列模式,一个生产者、一个队列、多个消费者。

就像老板发布了一堆任务,RabbitMQ 会把任务依次分配给员工,但是一个任务只会被一个员工完成。

发布订阅模式

你:这样效率就高多了!

但如果老板要求所有员工都写工作总结,怎么把同样的任务发给多个员工呢?

鱼皮:好问题!之前工作队列是多个员工共享一个任务列表,而现在每个员工都要有自己的任务队列。

老板需要利用 交换机(Exchange) 来控制把任务分发给哪些和它绑定的队列。

比如想把任务发给所有员工,就要用到 广播交换机(Fanout Exchange) ,它会把任务发给所有已绑定的队列,然后每个员工分别从自己的队列取任务并完成。这就是 发布订阅模式(Publish/Subscribe)

路由模式

你:那如果老板想把某些任务发给特定员工呢?比如鱼皮负责写代码和修 Bug,小阿巴负责写代码和摸鱼~

鱼皮:可以使用 路由模式(Routing) ,给每个员工的队列设置自己负责的路由键(Routing Key):

  • 鱼皮的队列绑定 "写代码" 和 "修 Bug"
  • 小阿巴的队列绑定 "写代码" 和 "摸鱼"

老板发布任务时会指定路由键,由 直接交换机(Direct Exchange) 根据路由键精确匹配,把任务发给对应的队列。

主题模式

你:那如果老板想把所有前端相关的任务都发给前端员工,后端相关的任务都发给后端员工呢?一个一个指定路由键是不是太麻烦了?

鱼皮:可以使用 主题模式(Topic) ,它使用 主题交换机(Topic Exchange) ,支持使用通配符模糊匹配。

可以给队列绑定通配符路由键,就能接收所有匹配的任务:

  • 前端员工的队列绑定 frontend.*(匹配 1 个词),能匹配 frontend.Vuefrontend.React
  • 后端员工的队列绑定 backend.#(匹配多个词),能匹配 backendbackend.Javabackend.Java.优化

你:哇,这样一来就灵活多了!

鱼皮:没错,这 5 种模式是企业中最常用的,掌握了它们就能应对大部分场景了。至于最后一种模式 ------ RPC(远程过程调用)模式,暂时不需要了解,因为企业开发中一般用专门的 RPC 框架,比如 gRPC、Dubbo。

你:好嘞,我先用这些工作模式来重构秒杀抢购功能,请好吧您嘞!

第四阶段:消息队列生产实践

一个月后,你意气风发地找到鱼皮:鱼皮 gie,我的抢购代码重构完了,快帮我看看能不能上线~

鱼皮看着你的代码,表情难受得像持矢一样:emmm,你这代码要是上线,公司就完蛋了!

你:阿巴阿巴,我本地测试过了,完全没问题啊!

鱼皮:消息队列在生产环境中的坑可多着呢!下面我来问你几个问题。

第一问:消息会丢吗?

鱼皮:如果重启 RabbitMQ 服务器,队列里的消息会丢吗?

你支支吾吾:会......会丢吧?

鱼皮:当然会!在抢购系统中,如果消息丢了,订单永远不会被创建,用户那边会一直显示 "抢购中"。

你着急了:那咋办啊,我会吃投诉的!

鱼皮:要保证消息不丢失,需要做好持久化 3 件套,把数据从内存保存到硬盘:

  • 队列持久化,创建队列时设置 durable 为 true。
  • 消息持久化,发送消息时设置消息为持久化模式(比如 deliveryMode = 2 或 persistent = true)
  • 交换机持久化,创建交换机时设置 durable 为 true。

你:哈哈,这下消息就不会丢了吧!

鱼皮:不一定!光持久化还不够,还要有消息确认机制来保证消息的可靠性。

1)生产者确认(Publisher Confirm):生产者发送消息后,等待 RabbitMQ 的确认回复,确保消息真的被接收了。就像寄快递,你把包裹交给快递员,快递员要给你一个回执单,证明他收到了。

2)消费者确认(Consumer ACK):消费者处理消息成功后,要手动告诉 RabbitMQ "我处理完了,你可以删了"。

千万别用默认的自动确认,那样消息一收到就删除,万一处理失败消息就丢了。就像收快递要签收,确保包裹真的送到你手上了。

鱼皮:这样从生产到消费的整个链路都有保障,消息就不会丢失了。

第二问:消息会重复吗?

鱼皮:如果网络抖动,或者消费者重启,同一条消息可能被消费多次。比如抢购消息被重复消费,同一个用户的订单被创建了 2 次,库存被扣了 2 次怎么办?

你:那我得跑路了!

鱼皮:不至于不至于,我们要保证 消息幂等性,让重复消费等同于只消费一次。

常见的方案有 3 种:

1)给每条消息一个唯一 ID(比如 UUID 或雪花算法 ID),消费前先检查这个 ID 是否处理过。

2)利用数据库唯一索引,比如订单号设置为唯一索引,重复插入会失败。

3)使用 Redis 分布式锁,同一条消息同一时间只能有一个消费者处理。

你:明白了!抢购时为了防止重复下单,要检查用户是否已经下过单了。

鱼皮点头:没错,幂等性设计是分布式系统的基本功。

第三问:消息乱序怎么办?

鱼皮:比如用户先抢购下单、然后取消订单,分别向队列发了 "创建订单" 和 "取消订单" 2 条消息。如果处理顺序乱了,系统先处理取消、后处理创建,订单状态就错了。

你:队列不是先进先出的吗?RabbitMQ 应该天然有序吧?

鱼皮:单队列内确实有序,但如果你开了多个消费者并发处理,可能消息 1 还在处理,消息 2 已经处理完了,顺序就乱了。

你:那怎么保证顺序呢?

鱼皮:在 RabbitMQ 中,要严格保证顺序,建议用 单队列 + 单消费者

你:那性能不就很低了吗?

鱼皮:没错,所以要根据业务需求权衡一致性和性能。

如果你全都要,可以考虑 Kafka 的分区机制,可以将同一用户的消息路由到同一个分区,同一个分区内的消息严格有序,不同用户的消息又可以并发处理。

你:妙啊,又学到一个架构知识!

第四问:消息处理失败怎么办?

鱼皮:如果消费者处理消息时出错了,比如数据库连接失败、业务逻辑异常,怎么办呢?

你:重试?

鱼皮:重试几次还是失败呢?

你:阿巴阿巴,直接删掉消息?

鱼皮:删掉不就丢了吗?!这时应该要用死信队列(Dead Letter Queue)。

3 种情况会产生死信:

  1. 消息被消费者拒绝(reject 或 nack,requeue 参数设置为 false)
  2. 消息过期
  3. 队列满了

你:呜呜呜,这些死信好可怜。

鱼皮:没错,我们要给死信一个去处。可以配置死信交换机(DLX),将死信自动路由到死信队列。由专门的消费者监控死信队列,发现死信后,可以重试、告警、或者人工处理。

你:好耶,这样异常消息就不会丢失啦!

第五问:RabbitMQ 服务挂了怎么办?

鱼皮:前面说了这么多保证消息不丢的机制,但如果 RabbitMQ 服务本身挂了,整个系统就不能收发消息了,这可是大事故!

你汗流浃背了:那怎么办?

这时,练习两年的实习生阿坤突然鸡叫起来:我知道,要搭建集群和高可用架构!

生产环境至少要搭建 3 个 RabbitMQ 节点的集群。

对于重要的队列,要使用 Quorum 仲裁队列,它基于 Raft 协议实现,会把数据自动同步到多个节点,保证数据一致性。

如果主节点挂了,Raft 会自动选举新的主节点,实现故障转移,用户毫无感知。

如果数据量太大,单个队列存不下,可以使用 Sharding 插件创建 分片队列,把消息分散到多个节点。不过 RabbitMQ 并不擅长这个场景,建议使用 Kafka。

鱼皮拍了拍阿坤的肩膀:不错!生产环境的高可用是非常重要的。

此外,RabbitMQ 还有一些高级特性,在特定场景下很有用。

RabbitMQ 高级特性

1)延迟队列

比如想要自动取消超过 15 分钟还未支付的订单,可以用死信队列配合生存时间(TTL)实现。发消息时设置 TTL 为 15 分钟,等它过期变成死信,自动进入死信队列,然后让死信队列的消费者处理取消逻辑。但是更推荐使用专门的延迟插件 rabbitmq_delayed_message_exchange

2)优先级队列

比如想优先处理 VIP 用户的订单,可以设置队列的最大优先级(x-max-priority),然后在发送消息时指定优先级,优先级高的消息会被优先消费。

3)Stream 流式存储

传统队列消息消费后就删除了,而 Stream 可以保留历史消息、重复消费、回溯历史,类似 Kafka,适用于实时数据分析、审计日志等场景。但我建议了解即可,不如用 Kafka。

你羞愧地低下了头:我以为自己已经掌握了 RabbitMQ,原来只是学了个皮毛...

第五阶段:深入原理

被鱼皮连环拷问后,你主动找到阿坤:坤哥你好强,我想深入学习 RabbitMQ 底层原理,请问你是咋学的啊?

阿坤有些惊讶:咦?你不背八股文的么?刷刷题 就好了呀!

你震惊了:现在的校招生,竟然恐怖如斯!

鱼皮:阿坤你别逗他了,其实可以带着问题学习,重点探索 RabbitMQ 的消息路由机制、队列存储结构、AMQP 协议和消息持久化的实现。

比如:

  1. 消息路由机制:Exchange 用什么算法匹配?Binding 如何存储?
  2. 队列存储结构:消息在内存还是磁盘?不同队列类型有什么区别?
  3. AMQP 协议:客户端和服务端怎么通信?数据格式是什么样的?
  4. 持久化实现:数据怎么写入磁盘?如何保证不丢失?

你好奇:那要怎么学习这些原理呢?

鱼皮:从这些问题出发,去阅读相关的文章,推荐官方文档和官方博客。

或者像阿坤说的刷一刷 RabbitMQ 面试题,就能快速学会很多核心知识点。

如果想增加求职竞争力,最重要的是做实战项目,我在 编程导航 上的的智能 BI 项目和 OJ 判题系统项目都有完整的 RabbitMQ 实战。

你握紧了粉拳:好的,我这就去学!

结尾

若干年后,你已经成为了大厂的消息队列专家。不仅能熟练使用 RabbitMQ 解决各种业务问题,搭个集群架构也是手拿把掐的。

你也像鱼皮当时一样,耐心地给新人分享学习 RabbitMQ 的经验,让他们谨记 "消息队列是实战型技术,一定要多动手实践"。

再次遇到鱼皮是在一条昏暗的小巷,此时的他年过 35,一毛不拔。你什么都没说,只是给他点了个赞。

不打扰,是你的温柔。

更多

💻 编程学习交流:编程导航 📃 简历快速制作:老鱼简历 ✏️ 面试刷题神器:面试鸭

相关推荐
yuzhiboyouye3 分钟前
内连接,左连接,右连接怎么区别开来?
数据库
铭毅天下18 分钟前
Easysearch 版本进化全图——从 ES 国产替代到 AI Native 搜索数据库
大数据·数据库·人工智能·elasticsearch·搜索引擎
muddjsv25 分钟前
SQL 最常用技能详解与实战示例
数据库·sql·mysql
我要改名叫嘟嘟1 小时前
“如果喜欢一本书,你会重复阅读它吗?”
程序员
muddjsv2 小时前
大中小型企业数据配置年度成本估算分析
数据库·企业运营
塔能物联运维2 小时前
存量机房升级成为行业主流方向:热管理重构算力中心价值路径
数据库
lqj_本人2 小时前
鸿蒙electron跨端框架PC工志簿实战:项目、工时、阻塞和下一步都要有位置
数据库·华为·harmonyos
刘一说2 小时前
AI科技热点日报 | 2026年5月22日
数据库·人工智能·科技
LCG元3 小时前
RAG工程指南:从基础检索到生产部署全解析
java·运维·数据库
godspeed_lucip3 小时前
LLM和Agent——专题3: Agentic Workflow 入门(1)
大数据·数据库·人工智能