RabbitMQ 从入门到实战:详解安装、五种消息模型及持久化

一、RabbitMQ 核心介绍

1. 什么是 MQ?

**MQ (Message Queue,消息队列)**​ 是一种消息中间件,主要用于在微服务或分布式系统之间进行异步通信。

  • 核心作用:通过"发送者 -> 队列 -> 消费者"的模式,实现服务间的解耦。

2. 什么是 AMQP?

**AMQP (Advanced Message Queuing Protocol)**​ 即高级消息队列协议。RabbitMQ 是基于此协议实现的。

在 RabbitMQ 中,主要包含以下几个核心概念:

  • Connection(连接):类似于一条高速公路(如京港澳高速)。

  • Channel(信道):建立在 Connection 之上的虚拟连接,类似于公路上的车道。大部分 API 操作都在 Channel 中进行,它是复用的,减少了建立 TCP 连接的开销。

  • Queue(队列):存储消息的容器,消息最终在这里等待被消费。

  • Exchange(交换机):负责接收生产者发送的消息,并根据路由规则将消息分发到一个或多个队列中。

3. 什么是 RabbitMQ?

RabbitMQ 是使用 Erlang 语言编写的一款开源消息代理软件,它实现了 AMQP 协议,具有高性能、高可用性和易用性等特点。

4. 为什么要使用 MQ?

引入 MQ 主要为了解决以下问题:

  • 解耦:服务 A 原本需要调用 B 和 C。如果新增 D 服务,只需让 D 监听队列即可,无需修改 A 的代码。

  • 异步:服务 A 将消息发送到 MQ 后即可返回,B 和 C 服务异步消费消息进行处理,提升了响应速度。

  • 削峰:在高并发场景下,请求先进入 MQ,后端服务根据自己的处理能力慢慢拉取消息,防止系统被瞬时流量冲垮。

5. Spring Boot 整合

在 Spring Boot 项目中,通常使用起步依赖:

复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

二、RabbitMQ 安装与配置 (Linux/CentOS)

1. 安装 Erlang 环境

RabbitMQ 依赖 Erlang,需先安装:

复制代码
cd /usr/upload
rpm -ivh esl-erlang-17.3-1.x86_64.rpm --force --nodeps
rpm -ivh esl-erlang_17.3-1~centos~6_amd64.rpm --force --nodeps
rpm -ivh esl-erlang-compat-R14B-1.el6.noarch.rpm --force --nodeps

2. 安装 RabbitMQ Server

复制代码
rpm -ivh rabbitmq-server-3.4.1-1.noarch.rpm

3. 服务管理

复制代码
# 启动服务
service rabbitmq-server start
# 查看状态
service rabbitmq-server status
# 设置开机自启
chkconfig rabbitmq-server on
# 停止服务
service rabbitmq-server stop
# 重启服务
service rabbitmq-server restart

4. 启用后台管理界面

RabbitMQ 提供了一个 Web 管理界面,非常方便:

复制代码
rabbitmq-plugins enable rabbitmq_management
service rabbitmq-server restart

5. 用户管理

默认的 guest用户通常只允许本地访问,建议创建新管理员:

复制代码
# 创建用户 admin,密码 1111
rabbitmqctl add_user admin 1111
# 设置用户角色为管理员
rabbitmqctl set_user_tags admin administrator
# 设置权限 (允许访问默认vhost "/",并赋予所有权限)
rabbitmqctl set_permissions -p "/" admin ".*" ".*" ".*"
# 查看用户列表
rabbitmqctl list_users

6. 访问测试

浏览器访问:http://<你的服务器IP>:15672

使用刚创建的 admin/1111登录。


三、五种核心消息模型

1. Simple 简单模型

结构Producer -> Queue -> Consumer

这是最简单的模型,一对一发送。

关键问题:如何保证消息被成功消费?

  • 答案 :使用 手动 ACK (Acknowledge)

  • 默认是自动ACK,即消息一旦被消费端收到就认为成功。如果消费过程中报错,消息就丢了。

  • 手动ACK代码示例

    复制代码
    // 第二个参数 autoAck 设为 false
    channel.basicConsume(queueName, false, new DefaultConsumer(channel) {
        @Override
        public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
            try {
                // 业务逻辑处理
                System.out.println("Received: " + new String(body));
                // 手动确认:参数1是消息标签,参数2是是否批量确认
                channel.basicAck(envelope.getDeliveryTag(), false);
            } catch (Exception e) {
                // 异常处理,可以选择拒绝或重回队列
            }
        }
    });

2. Work 工作模型

结构Producer -> Queue -> 多个 Consumer

多个消费者竞争消费同一个队列中的消息。

关键问题:如何防止消息堆积?

  • 答案 :采用 **能者多劳 (Prefetch Count)**​ 策略。

  • 默认情况下,RabbitMQ 会按顺序将消息平均分给消费者(轮询)。如果某个消费者处理慢,会导致堆积。

  • 解决方案 :设置 channel.basicQos(1)。意思是:在我没有确认当前消息处理完之前,不要再给我发新的消息。这样处理快的人就会多干点活。

3. Fanout 广播模型

结构Producer -> Exchange -> (绑定) -> 多个 Queue -> 多个 Consumer

  • 特点:不处理路由键,只需要将队列绑定到交换机上。发送到交换机的消息会被转发到所有与该交换机绑定的队列上。

  • 注意:如果 Exchange 没有绑定任何 Queue,消息会被直接丢弃。

4. Direct 定向模型

结构Producer -> Exchange (RoutingKey) -> Queue -> Consumer

  • 特点 :通过 **Routing Key (路由键)**​ 来控制消息的分发。

  • 队列在绑定交换机时,需要指定一个 Binding Key。只有当消息的 Routing Key 与 Binding Key 完全匹配时,消息才会被路由到该队列。

5. Topic 通配符模型

结构Producer -> Exchange (Pattern) -> Queue -> Consumer

  • 特点:Topic 是 Direct 的扩展,支持通配符匹配。

  • 通配符规则

    • *:匹配一个单词(用 .分隔)。

    • #:匹配零个或多个单词。

  • 示例

    • Routing Key 为 user.news可以匹配 *.newsuser.#

四、持久化机制(数据安全)

为了保证 RabbitMQ 重启后消息不丢失,我们需要做三层持久化:

1. Exchange 持久化

在声明交换机时,将 durable参数设置为 true

复制代码
// 第三个参数为 durable (是否持久化)
channel.exchangeDeclare(EXCHANGE_NAME, "direct", true);

2. Queue 持久化

在声明队列时,同样设置持久化。

复制代码
// 第二个参数为 durable
channel.queueDeclare(QUEUE_NAME, true, false, false, null);

3. 消息持久化

在发送消息时,设置消息属性为持久化。

复制代码
// 使用 MessageProperties.PERSISTENT_TEXT_PLAIN 表示持久化
channel.basicPublish(EXCHANGE_NAME, ROUTING_KEY, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());

总结 :保证消息不丢的终极方案 = 手动ACK(应对消费失败) ​ + 持久化(应对MQ宕机)


💡 发布建议

这篇文章结构已经很清晰了。如果你打算发布,建议在开头加一段"前言",简单说说你为什么学 RabbitMQ,或者在结尾加个"总结",这样更容易获得读者的收藏和点赞哦!

相关推荐
Francek Chen2 小时前
【大数据存储与管理】云数据库:03 云数据库系统架构
大数据·数据库·分布式·架构
2601_957786772 小时前
AI 原生营销矩阵系统:分布式素材管理与多租户权限控制技术实现
人工智能·分布式·矩阵
appearappear2 小时前
乐观锁与分布式的理解
分布式
老码观察2 小时前
数环通消息中间件选型实录:RocketMQ vs Kafka vs RabbitMQ,我们为什么选了RocketMQ
kafka·rabbitmq·rocketmq
huaiixinsi3 小时前
Canal + Outbox、Kafka 选型与高可用、Caffeine 底层原理总结
java·数据库·分布式·mysql·spring·adb·kafka
许长安3 小时前
Kafka 架构讲解:从提交日志到分区副本机制
c++·经验分享·笔记·分布式·架构·kafka
qq_297574673 小时前
第十二篇:RabbitMQ消息积压问题——排查与解决方案(实战优化)
分布式·rabbitmq
qq_297574673 小时前
第十三篇:RabbitMQ限流与熔断——保护系统稳定性
分布式·rabbitmq·ruby
菜鸟小九3 小时前
Kafka()
分布式·kafka