Skip to content

这是我学习 RabbitMQ 时整理的入门笔记。消息队列是分布式系统里绕不开的组件,秒杀系统的异步削峰、订单超时、日志收集、应用解耦都用它。这篇先把 RabbitMQ 的核心概念和上手流程过一遍,代码按 Spring Boot 落地。


一、为什么需要消息队列

先把"解决什么问题"想清楚,否则学了概念也不知道用在哪。消息队列解决三类问题:

  1. 异步削峰:秒杀下单一瞬间流量巨大,直接同步写库会打爆数据库。先丢进队列,消费者按自己的速度慢慢处理——把"瞬间高峰"变成"平稳流量"。
  2. 应用解耦:下单后要发短信、发邮件、更新库存。如果同步调用,任何一个下游挂掉或变慢都会拖垮主流程;通过队列,主流程只依赖队列,下游自己订阅。
  3. 流量削峰/缓冲:日志采集、大数据上报这种"量大但不紧急"的场景,队列做缓冲,消费者批量处理。

一句话:生产者不关心谁在消费,消费者不关心谁在发消息,中间只有队列。

二、核心概念(先记这六个)

RabbitMQ 的模型可以拆成六个词,记住它们就懂了大半:

概念说明
Producer(生产者)发消息的一方
Consumer(消费者)收消息并处理的一方
Queue(队列)消息的暂存地,本质是一个有界/无界缓冲
Exchange(交换机)消息的"路由器",决定消息发给哪些队列
Binding(绑定)交换机和队列之间的连接关系(带路由规则)
Routing Key(路由键)消息携带的"地址",交换机按它路由

消息流转:Producer → Exchange →(按 Binding 规则)→ Queue → Consumer

注意:生产者从来不直接往队列发消息,而是发给交换机,交换机按绑定规则把消息路由到队列——这是 RabbitMQ 和 Redis 的 List 这类"直接队列"最大的区别。

三、交换机类型(重点)

交换机是 RabbitMQ 的核心,一共四种类型,决定了消息怎么路由:

类型路由规则典型场景
DirectRouting Key 精确匹配按业务类型精确分发
Fanout忽略 Routing Key,广播给所有绑定队列广播通知
TopicRouting Key 通配符匹配* 一个词,# 多个词)按主题订阅(如 order.*
Headers按消息头(Header)匹配很少用,一般被 Topic 替代

理解 Fanout 和 Topic 的差别就够了

  • Fanout:发一条,所有绑定的队列都收到(广播,无差别)
  • Topic:发一条带路由键的消息(如 order.created),只有绑定了匹配模式的队列收到(order.* 收,payment.* 不收)

四、Docker 安装 + 管理界面

本地开发用 Docker 一条命令起:

bash
docker run -d --name rabbitmq \
  -p 5672:5672 -p 15672:15672 \
  rabbitmq:3.13-management
  • 5672AMQP 协议端口(程序连接用)
  • 15672:管理界面端口(浏览器访问 http://localhost:15672,默认账号 guest/guest

管理界面里能看到队列、交换机、连接、消息积压量,排查问题第一站。

五、Spring Boot 集成实战

1. 依赖

xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

2. 配置

yaml
spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest

3. 声明交换机、队列、绑定(Java Config)

java
@Configuration
public class RabbitConfig {

    public static final String EXCHANGE = "demo.exchange";
    public static final String QUEUE = "demo.queue";
    public static final String ROUTING_KEY = "demo.rk";

    @Bean
    public DirectExchange demoExchange() {
        // durable=true:交换机持久化,重启不丢
        return new DirectExchange(EXCHANGE, true, false);
    }

    @Bean
    public Queue demoQueue() {
        // durable=true:队列持久化(存到磁盘)
        return new Queue(QUEUE, true);
    }

    @Bean
    public Binding demoBinding() {
        return BindingBuilder.bind(demoQueue()).to(demoExchange()).with(ROUTING_KEY);
    }
}

4. 发送消息

java
@Service
public class MsgSender {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void send(String msg) {
        rabbitTemplate.convertAndSend(
            RabbitConfig.EXCHANGE,
            RabbitConfig.ROUTING_KEY,
            msg
        );
    }
}

5. 接收消息(消费者)

java
@Component
public class MsgListener {

    @RabbitListener(queues = RabbitConfig.QUEUE)
    public void onMessage(String message) {
        System.out.println("收到消息: " + message);
    }
}

启动应用,调一次 send(),控制台就能看到消费者打印——最简单的生产者/消费者链路就跑通了。

六、入门就要知道的三个"坑"

这几个问题初学者几乎必踩,先打个预防针(详细方案见我整理的系统架构 FAQ 里"消息队列怎么防丢消息"一节):

  1. 消息丢了:生产者没开 confirm、队列/消息没设置持久化、消费者自动 ack 后处理失败——三层里任何一层漏了都会丢。
  2. 重复消费:MQ 只保证"至少一次",消费者必须自己做幂等(唯一键/状态机),别指望 MQ 不重投。
  3. 乱序:RabbitMQ 单队列单消费者天然有序;多消费者抢消息就可能乱序,需要业务侧排序或保证单消费者。

小结

  • RabbitMQ = 交换机路由的消息队列,六个核心概念(生产者/消费者/队列/交换机/绑定/路由键)
  • 四种交换机:Direct 精确匹配、Fanout 广播、Topic 通配符、Headers 按头(少用)
  • Spring Boot 集成三步:依赖 + 配置 + 声明交换机/队列/绑定,RabbitTemplate 发、@RabbitListener
  • 生产可用三件事:持久化 + 手动 ack + 消费者幂等

下一步可以看我的《秒杀系统架构分析》里 RabbitMQ 怎么在真实场景做异步削峰,或者深入研究死信队列、延迟队列(插件)、消息确认机制。