一、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可以匹配*.news或user.#。
- Routing Key 为
四、持久化机制(数据安全)
为了保证 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,或者在结尾加个"总结",这样更容易获得读者的收藏和点赞哦!