RabbitMQ 是一个开源的、基于 Erlang 语言实现的消息队列中间件,使用高级消息队列协议(AMQP)进行通信。它在分布式系统中用于解耦应用程序、提升异步通信能力、提高系统可扩展性与可靠性。
传统的组件之间直接调用(REST、RPC 等)导致: 高耗耗,并发性差,系统耦合性差,故障传播,需要一种可靠的、异步的、组件解耦的中间件。RabbitMQ 就是在这样的需求下,基于 AMQP 标准,为解决分布式应用的消息通信提供稳定性和扩展性。
RabbitMQ 消息队列的使用场景非常广泛,核心作用在于解耦、削峰、异步处理。下面是一个典型的使用场景示例:
# 📦 使用场景:下单后异步发送短信通知
场景描述:
用户在电商网站下单后,系统需要给用户发送一条"下单成功"的短信。传统做法是下单成功后立刻调用短信接口发送。但如果短信服务延迟或失败,会直接影响用户下单体验。
✅ 引入 RabbitMQ 解决方式:
1.用户下单成功后,系统将"发送短信任务"放入 RabbitMQ 的队列中;
2.短信服务是一个独立的消费者进程,监听这个队列;
3.一旦有消息进入队列,消费者接收并调用短信服务发送短信。
🎯 优点:
• 解耦合:下单逻辑与短信逻辑分离;
• 提高性能:下单接口响应快,不必等待短信接口;
• 具备容错性:如果短信服务临时宕机,消息仍保存在队列中,不会丢失。
RabbitMQ 快速实践
一.普通安装
RabbitMQ安装配置过程详解(Linux版)
1、介绍:
本次RabbitMQ安装环境相关信息:
Linux CentOS 7版本
erlang-21.3-1.el7.x86_64.rpm
rabbitmq-server-3.8.8-1.el7.noarch.rpm
RabbitMQ的底层源码是基于erlang语言开发的,因此安装rabbitMQ需要依赖erlang语言环境.
2、下载安装程序
当erlang和rabbitmq所安装的版本不对应时,可能会无法正常运行,为此安装所需要的Linux版本的erlang和rabbitmq对应安装包已经整理于网盘中,下载地址如下,若提取码失效,还请及时联系:
链接:https://pan.baidu.com/s/1NxK78QASAvlM48vkU4FXAw
提取码:x6ld
将下载好的压缩包通过Xftp上传至/home/rabbitmq 目录下(如果没有 rabbitmq 需要自己创建)

3、文件安装
3.1 rpm方式安装erlang:
bash
rpm -ivh erlang-21.3-1.el7.x86_64.rpm
安装socat 依赖
bash
yum -y install socat
在通过yum安装时,可能会由于源的问题,centos7目前无法通过yum进行联网安装软件:具体解决方法如下:
bash
# 1、将yum的源改成阿里云的,直接在命令行输入:
curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
# 2、运行 yum clean all
yum clean all
# 3、生成yum缓存
yum makecache
# 4、 可以通过yum repolist来查询yum的状态
yum repolist
yum问题解决之后,运行 yum -y install socat,安装成功
bash
yum -y install socat
安装RabbitMQ
bash
rpm -ivh rabbitmq-server-3.8.8-1.el7.noarch.rpm
RabbitMQ的启动 停止命令:
bash
# 添加开机启动 RabbitMQ 服务
chkconfig rabbitmq-server on
# 启动 RabbitMQ 服务
/sbin/service rabbitmq-server start
# 停止服务(选择执行)
/sbin/service rabbitmq-server stop
# 查看服务状态
/sbin/service rabbitmq-server status
在启动RabbtMQ之前,开启web插件管理,开启之后可以通过http://localhost:15672 来访问rabbitMQ的页面
开启 web 管理插件
rabbitmq-plugins enable rabbitmq_management
登录前端控制界面
再登录之前,先确保RabbitMQ的服务是出于开启的状态,可以通过上述的服务器查看和开启命令自行查看。
由于我的Linux部署在阿里云服务器上,访问地址为 阿里云的公网ip地址:15672端口,默认初始化用户名和密码均为guest,
此外,由于是远程登录阿里云服务器,需要设置阿里云安全组开启15672端口,开启之后便可正常登录。在登录的时候会出现权限问题,无法登录:
添加一个新的用户
出现上述登录时权限问题,需要创建一个新的用户,并设置用户角色和权限,具体步骤如下:
bash
# 创建账号 设置用户名和密码
rabbitmqctl add_user admin 123
# 设置用户角色
rabbitmqctl set_user_tags admin administrator
# 设置用户权限 set_permissions [-p <vhostpath>] <user> <conf> <write> <read>
rabbitmqctl set_permissions -p "/" admin ".*" ".*" ".*"
# 上述命令使得用户 user_admin 具有/vhost1 这个 virtual host 中所有资源的配置、写、读权限
# 当前用户和角色
rabbitmqctl list_users
使用新建的用户admin进行登录
附加命令:
bash
# 关闭应用的命令为
rabbitmqctl stop_app
# 清除的命令为
rabbitmqctl reset
# 重新启动命令为
rabbitmqctl start_app
二. RabbitMQ Docker 快速部署指南
# 这里下载最新的,如果需要指定版本,后缀指定即可
docker search rabbitmq
docker pull rabbitmq
docker pull rabbitmq:指定的版本
# 启动 mq 【-v 将文件挂载至宿主机器上】
docker run \
--privileged=true \
-d \
-p 5672:5672 \
-p 15672:15672 \
--name rabbitmq \
--restart=always \
--hostname rabbitmq \
rabbitmq
#参数说明:
#--privileged=true:赋予容器特权模式(有安全隐患,生产环境慎用)
#-d:以守护进程方式运行容器
#-p 5672:5672:映射 AMQP 协议端口
#-p 15672:15672:映射管理界面端口
#--name rabbitmq:指定容器名称
#--restart=always:设置容器自动重启策略
#--hostname:设置容器主机名
# 启动容器后,进入容器启动管理页面
docker exec -it rabbitmq rabbitmq-plugins enable rabbitmq_management
# 启用管理界面的指标收集功能,然后重启容器使配置生效
docker exec -it rabbitmq bash
cd /etc/rabbitmq/conf.d/
echo management_agent.disable_metrics_collector = false > 20-management_agent.disable_metrics_collector.conf
exit
docker restart rabbitmq
# 浏览器访问 http://127.0.0.1:15672/#/
# 初始账号密码 guest guest
以 Spring Boot + RabbitMQ 为例:
# Maven 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
# application.yml 配置
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
# virtual-host: my_vhost
# 消息发送者
@Service
public class Sender {
@Autowired
private RabbitTemplate rabbitTemplate;
public void send(String message) {
rabbitTemplate.convertAndSend("testQueue", message);
}
}
# 消息接收者
@Component
public class Receiver {
@RabbitListener(queues = "testQueue")
public void receive(String message) {
System.out.println("Received: " + message);
}
}
# 初始化队列
@Configuration
public class RabbitConfig {
@Bean
public Queue testQueue() {
return new Queue("testQueue");
}
}
MQ常用命令
# RabbitMQ 服务管理命令(需在容器内执行)
# 1. 启停服务
rabbitmq-server # 启动服务(容器内通常不需要手动执行)
rabbitmqctl stop # 停止服务
# 2. 插件管理
rabbitmq-plugins list # 列出所有插件
rabbitmq-plugins enable rabbitmq_management # 启用管理界面
rabbitmq-plugins disable <插件名> # 禁用插件
# 3. 状态检查
rabbitmqctl status # 查看服务状态
rabbitmqctl cluster_status # 查看集群状态
##################### 用户与权限管理 #################
# 1. 用户操作
rabbitmqctl list_users # 列出所有用户
rabbitmqctl add_user <用户名> <密码> # 创建用户
rabbitmqctl delete_user <用户名> # 删除用户
rabbitmqctl change_password <用户名> <新密码> # 修改密码
# 2. 设置用户角色(Tags)
RabbitMQ 角色分为以下几种:
administrator:超级管理员(可管理所有资源)
monitoring:监控者(可查看所有状态)
policymaker:策略管理者(可配置策略)
management:普通管理者(基础操作权限)
自定义角色(如 producer/consumer)
# 设置为管理员角色(最高权限)
rabbitmqctl set_user_tags admin administrator
# 如果需要多个角色(用空格分隔)
rabbitmqctl set_user_tags admin monitoring policymaker
# 3. 权限控制
# rabbitmqctl set_permissions -p <虚拟主机> <用户名> <配置权限> <写入权限> <读取权限>
rabbitmqctl list_permissions [-p <vhost>] # 查看权限
rabbitmqctl set_permissions -p <vhost> <用户> ".*" ".*" ".*" # 授予权限
rabbitmqctl clear_permissions -p <vhost> <用户> # 清除权限
权限说明:
".*":通配符表示所有资源
"^queue\.":正则表达式匹配特定资源(如所有队列)
# 4. 验证用户和权限
# 列出所有用户(显示用户名和角色)
rabbitmqctl list_users
# 查看特定用户的权限
rabbitmqctl list_permissions -p "/" admin
# 查看所有虚拟主机的权限
rabbitmqctl list_permissions
##################### 虚拟主机(VHost)管理 #################
rabbitmqctl list_vhosts # 列出所有虚拟主机
rabbitmqctl add_vhost <vhost名> # 创建虚拟主机
rabbitmqctl delete_vhost <vhost名> # 删除虚拟主机
##################### 队列与交换机管理 #################
# 1. 查看队列/交换机
rabbitmqctl list_queues [-p <vhost>] # 列出队列
rabbitmqctl list_exchanges [-p <vhost>] # 列出交换机
rabbitmqctl list_bindings [-p <vhost>] # 列出绑定关系
# 2. 清理队列
rabbitmqctl purge_queue <队列名> # 清空队列中的消息
##################### 其他 #################
# 1. 重置节点(危险操作!)
rabbitmqctl reset # 重置节点(会删除所有数据和配置)
# 2. 日志查看
tail -f /var/log/rabbitmq/rabbitmq.log # 查看日志(容器内路径)
##################### HTTP API 管理(无需进入容器) #################
# 通过 curl 调用管理 API(需先启用 rabbitmq_management 插件):
curl -u admin:admin http://localhost:15672/api/queues # 获取队列列表
# 常见使用场景示例:
# 1. 创建用户并授权:
rabbitmqctl add_user user1 pass123
rabbitmqctl set_permissions -p / user1 ".*" ".*" ".*"
# 2. 监控队列积压消息数:
rabbitmqctl list_queues name messages_ready
# 备份与恢复:
备份定义:rabbitmqctl export_definitions /backup/rabbitmq_defs.json
恢复定义:rabbitmqctl import_definitions /backup/rabbitmq_defs.json
RabbitMQ 核心概念及关系
# 1. Queue(队列)
• 消息的最终存储地点。
• 消费者只能从队列中获取消息。
• 每条消息只会被一个消费者获取(除非使用特殊机制如镜像队列)。
# 2. Exchange(交换机)
• 接收生产者发送的消息,并根据路由规则转发到一个或多个队列。
• 不存储消息,只负责转发。
• 有四种类型:
• fanout:广播消息到所有绑定队列
• direct:根据精确的 routing key 匹配转发
• topic:支持模糊匹配的 routing key(带 * 和 #)
• headers:基于消息 header 的键值匹配(较少使用)
# 3. Routing Key(路由键)
• 是一段字符串,生产者在发送消息时指定。
• 交换机根据 routing key 与绑定关系(binding)进行匹配,将消息转发到相应队列。
# 4. Binding(绑定)
• 是交换机与队列之间建立的连接关系。
• 绑定时可以指定 routing key 或匹配模式(取决于交换机类型)。
• 一台交换机可以绑定多个队列。
# 5. Producer(生产者)
• 向交换机发送消息,必须指定:
• 目标交换机
• routing key
• 消息内容(body)
# 6. Consumer(消费者)
• 从队列中消费消息。
• 每个消费者监听一个或多个队列。
# 7. Virtual Host(虚拟主机)
• 类似于命名空间,用于隔离资源。
• 一个 RabbitMQ 实例中可以有多个 vhost,每个 vhost 中有独立的交换机、队列、绑定等。
# 8. Message(消息)
• 消息体是实际传输的数据内容(通常是字符串、JSON、二进制等)。
• 消息中还包含 headers、properties(比如持久性、优先级、过期时间等)。
# 9. Acknowledgment(消息确认)
• 消费者从队列中获取消息后需要确认(ack),表示处理完成。
• 如果未 ack,消息可以重新投递。
• 支持自动确认或手动确认。
# 10. Durability(持久性)
• 队列和消息都可以设置是否持久化:
• 队列 durable = true → RabbitMQ 重启后队列仍在。
• 消息 delivery_mode = 2 → 消息将写入磁盘。
# 🔁 它们之间的关系
[Producer] --(routingKey)--> [Exchange] --(binding with routingKey)--> [Queue] --> [Consumer]
简要流程:
1.Producer 向 Exchange 发送消息,指定 routing key。
2.Exchange 根据自身类型和绑定规则,决定将消息路由到哪些 Queue。
3.Queue 存储消息,等待 Consumer 消费。
4.Consumer 从 Queue 中拉取或订阅消息,处理后确认(ack)。
RabbitMQ 中 4 种交换机类型(Exchange Type)
类型 | 描述 | 路由方式 | 是否依赖 routingKey | 多播支持 | 匹配灵活性 |
---|---|---|---|---|---|
fanout | 广播式 | 所有绑定的队列都接收消息 | 否 | 是 | 无 |
direct | 精确路由 | routingKey 完全匹配 | 是 | 否 | 精确匹配 |
topic | 模糊匹配路由 | routingKey 模式匹配 | 是 | 可多个 | 高 |
headers | 基于消息 headers 匹配 | 匹配 headers 的键值对 | 否 | 是 | 非常高 |
RabbitMQ 消息运行模式的七种模型
# 🧩 1. 简单模式(Simple / Hello World)
简介:
最基础的一种模式,一个生产者发送消息到队列,一个消费者从队列中接收消息。
特点:
• 一对一通信
• 没有 Exchange(使用默认的)
• 队列名称需匹配
场景:
适合快速测试和入门练习,或简单的一对一消息处理。
Producer --> [Queue] --> Consumer
# 🧩 2. 工作队列模式(Work Queues / Task Queue)
简介:
多个消费者从同一个队列获取任务,实现负载均衡。
特点:
• 一个队列,多个消费者
• 每条消息只会被一个消费者处理
• 支持消息应答(ack)
场景:
适用于任务分发、后台异步处理,如图片处理、邮件发送等。
Producer --> [Queue] --> Consumer1
--> Consumer2
--> Consumer3
# 🧩 3. 发布/订阅模式(Publish/Subscribe / Fanout Exchange)
简介:
一个生产者将消息广播给多个队列,所有绑定的消费者都能收到消息。
特点:
• 使用 Fanout 类型 Exchange
• 每个队列绑定到 Exchange 上
• 消息发送到所有绑定的队列
场景:
适用于广播通知,比如系统日志同步、多个系统接收同一份数据等。
Producer --> [Fanout Exchange]
| |
[Queue1] [Queue2]
| |
Consumer1 Consumer2
# 🧩 4. 路由模式(Routing / Direct Exchange)
简介:
生产者根据路由键(Routing Key)将消息投递到不同的队列,消费者只接收指定路由键的消息。
特点:
• 使用 Direct 类型 Exchange
• 队列根据绑定的 routing key 接收消息
场景:
日志系统分类投递,比如"error"、"info"、"warning"等级日志只发送给指定服务。
Producer --[Direct Exchange]--(key="error")--> [Queue1] --> Consumer1
--(key="info")--> [Queue2] --> Consumer2
# 🧩 5. 通配符模式(Topics / Topic Exchange)
简介:
在路由模式基础上加入通配符匹配机制,增强路由灵活性。
特点:
• 使用 Topic 类型 Exchange
• Routing Key 支持 *(匹配一个词)和 #(匹配零个或多个词)
场景:
适用于需要更复杂的路由规则,如新闻订阅、设备数据分组等。
Producer --[Topic Exchange]--(key="user.*")--> [Queue1]
(key="user.#")--> [Queue2]
# 🧩 6. RPC 模式(Remote Procedure Call)
简介:
使用 RabbitMQ 实现远程调用请求/响应模式。客户端发送请求,服务端处理后响应。
特点:
• 客户端发送请求消息,附带回调队列和 correlationId
• 服务端返回响应到回调队列
• 客户端等待响应
场景:
实现微服务之间的 RPC 通信,如获取用户信息、远程调用计算服务等。
Client --> [Queue: rpc_request] --> Server
Server --> [Queue: callback_queue] --> Client
# 🧩 7. 发布确认(Publisher Confirms)
简介:
用于确保消息可靠性投递的机制,确保消息从生产者成功到达 Broker。
特点:
• 生产者发送消息后可以开启 confirm 模式
• Broker 接收到消息后会返回 ack/nack
• 可以结合批量确认或异步确认机制
场景:
适用于对消息可靠性要求高的场景,如金融交易、订单系统等。
Producer --[Confirm Select模式]--> Exchange
<-- Ack / Nack (Broker确认投递成功与否)
RabbitMQ 的 Java 和 Spring 示例
在 RabbitMQ 的 Java 客户端(amqp-client)中,几个核心类/接口是必须熟悉的,它们是构建生产者、消费者、交换机、队列等功能的基础。
RabbitMQ Java 客户端核心对象及 API 说明
类/接口 | 作用简述 |
---|---|
ConnectionFactory | 构建连接的工厂类,用于设置主机、端口、用户名、虚拟主机等 |
Connection | 表示客户端到 RabbitMQ 的一个连接 |
Channel | 通信通道,用于声明交换机/队列、发送消息、消费消息等 |
BuiltinExchangeType | 枚举类型,指定交换机类型:DIRECT、TOPIC、FANOUT、HEADERS |
AMQP.BasicProperties | 消息的元数据(持久化、优先级、headers 等) |
// Maven 依赖
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.20.0</version>
</dependency>
// 🔧 核心 API 常用用法
// 创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
factory.setUsername("guest");
factory.setPassword("guest");
// 建立连接
Connection connection = factory.newConnection();
// 创建通道
Channel channel = connection.createChannel();
// 声明交换机
channel.exchangeDeclare("my-exchange", BuiltinExchangeType.DIRECT, true);
// 声明队列
channel.queueDeclare("my-queue", true, false, false, null);
// 队列绑定到交换机
channel.queueBind("my-queue", "my-exchange", "my.routing.key");
// 发布消息
channel.basicPublish("my-exchange", "my.routing.key", null, "Hello".getBytes());
✅ 4种交换机的使用方式(含代码 + 路由说明)
# 🧰 公共工具类(连接工具)
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class RabbitUtil {
public static Connection getConnection() throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost"); // RabbitMQ 主机地址
factory.setPort(5672); // 默认端口
factory.setUsername("guest"); // 默认用户名
factory.setPassword("guest"); // 默认密码
factory.setVirtualHost("/"); // 默认虚拟主机
return factory.newConnection();
}
}
# 1️⃣ Fanout Exchange(广播交换机)
import com.rabbitmq.client.*;
public class FanoutExample {
public static void main(String[] args) throws Exception {
Connection connection = RabbitUtil.getConnection();
Channel channel = connection.createChannel();
String exchangeName = "ex.fanout";
String queue1 = "fanout.queue.1";
String queue2 = "fanout.queue.2";
// 声明交换机:类型为 FANOUT(广播)
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.FANOUT, true);
// 声明两个队列
channel.queueDeclare(queue1, true, false, false, null);
channel.queueDeclare(queue2, true, false, false, null);
// 将两个队列绑定到广播交换机(不需要 routing key)
channel.queueBind(queue1, exchangeName, "");
channel.queueBind(queue2, exchangeName, "");
// 发布消息:routingKey 无效,使用空字符串
String msg = "广播通知:系统即将维护!";
channel.basicPublish(exchangeName, "", null, msg.getBytes());
System.out.println("Fanout 消息发送成功!");
channel.close();
connection.close();
}
}
# 2️⃣ Direct Exchange(直连交换机)
import com.rabbitmq.client.*;
public class DirectExample {
public static void main(String[] args) throws Exception {
Connection connection = RabbitUtil.getConnection();
Channel channel = connection.createChannel();
String exchangeName = "ex.direct";
String queue = "direct.queue.error";
// 声明交换机:类型为 DIRECT
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.DIRECT, true);
// 声明队列
channel.queueDeclare(queue, true, false, false, null);
// 绑定:指定 routingKey 为 "error"
channel.queueBind(queue, exchangeName, "error");
// 发布一条错误日志
String msg = "ERROR:服务崩溃了!";
channel.basicPublish(exchangeName, "error", null, msg.getBytes());
System.out.println("Direct 消息发送成功!");
channel.close();
connection.close();
}
}
# 3️⃣ Topic Exchange(主题交换机)
import com.rabbitmq.client.*;
public class TopicExample {
public static void main(String[] args) throws Exception {
Connection connection = RabbitUtil.getConnection();
Channel channel = connection.createChannel();
String exchangeName = "ex.topic";
String queue = "topic.queue.orders";
// 声明交换机:类型为 TOPIC
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.TOPIC, true);
// 声明队列
channel.queueDeclare(queue, true, false, false, null);
// 绑定:接收所有 order 开头的消息(如 order.create, order.pay)
channel.queueBind(queue, exchangeName, "order.*");
// 发布一条订单创建的消息
String msg = "订单创建成功:#12345";
channel.basicPublish(exchangeName, "order.create", null, msg.getBytes());
System.out.println("Topic 消息发送成功!");
channel.close();
connection.close();
}
}
# 4️⃣ Headers Exchange(头部交换机)
import com.rabbitmq.client.*;
import java.util.HashMap;
import java.util.Map;
public class HeadersExample {
public static void main(String[] args) throws Exception {
Connection connection = RabbitUtil.getConnection();
Channel channel = connection.createChannel();
String exchangeName = "ex.headers";
String queue = "headers.queue";
// 声明交换机:类型为 HEADERS
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.HEADERS, true);
// 声明队列
channel.queueDeclare(queue, true, false, false, null);
// 设置绑定时要求 header 匹配所有条件
Map<String, Object> bindingArgs = new HashMap<>();
bindingArgs.put("x-match", "all"); // "all" 表示所有 header 都必须匹配
bindingArgs.put("format", "pdf");
bindingArgs.put("type", "report");
// 绑定队列到交换机,带绑定参数
channel.queueBind(queue, exchangeName, "", bindingArgs);
// 发送消息时设置 headers
AMQP.BasicProperties props = new AMQP.BasicProperties.Builder()
.headers(Map.of("format", "pdf", "type", "report"))
.build();
String msg = "PDF 报告已生成";
channel.basicPublish(exchangeName, "", props, msg.getBytes());
System.out.println("Headers 消息发送成功!");
channel.close();
connection.close();
}
}
在 Spring 中使用 RabbitMQ,我们通常借助 Spring AMQP 框架(它是基于 spring-rabbit 的封装)。它极大简化了连接配置、交换机/队列声明、消息发送与接收等操作。
🧩 一、Spring 中使用 RabbitMQ 的方式
# 1️⃣ 引入依赖
<!-- Maven 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
# 2️⃣ application.yml 配置
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
virtual-host: /
listener:
simple:
acknowledge-mode: manual # 启用手动确认
prefetch: 1 # 每次只拉取一条消息处理
publisher-confirm-type: correlated # 开启发布确认(confirm)
publisher-returns: true # 开启返回监听(return)
🚀 二、交换机、队列和绑定关系的声明(持久化)
Spring 提供声明式写法,所有声明的队列/交换机默认是持久化的(除非你设置 durable = false)
@Configuration
publicclass RabbitConfig {
// 1. 声明交换机(Topic类型)
@Bean
public TopicExchange topicExchange() {
returnnew TopicExchange("ex.topic", true, false);
}
// 2. 声明队列
@Bean
public Queue orderQueue() {
returnnew Queue("queue.order", true); // durable = true 表示持久化
}
// 3. 绑定交换机和队列
@Bean
public Binding binding() {
return BindingBuilder.bind(orderQueue())
.to(topicExchange())
.with("order.#"); // 通配 routingKey
}
}
📬 三、发送消息(带持久化标志 & 确认)
@Service
publicclass OrderProducer {
@Autowired
private RabbitTemplate rabbitTemplate;
// 消息发送(持久化 + 回调确认)
public void sendOrder(String orderJson) {
MessageProperties props = new MessageProperties();
props.setDeliveryMode(MessageDeliveryMode.PERSISTENT); // 消息持久化
Message message = new Message(orderJson.getBytes(), props);
rabbitTemplate.convertAndSend("ex.topic", "order.created", message);
}
}
@Component
publicclass ConfirmCallbackHandler implements RabbitTemplate.ConfirmCallback {
@Autowired
public ConfirmCallbackHandler(RabbitTemplate rabbitTemplate) {
rabbitTemplate.setConfirmCallback(this); // 注入回调
}
// **✅ 发布确认回调(confirm)**
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
if (ack) {
System.out.println("消息发送成功!");
} else {
System.out.println("消息发送失败,原因:" + cause);
}
}
// ✅ Return 回调(不可路由)
@Override
public void returnedMessage(Message message, int replyCode, String replyText,
String exchange, String routingKey) {
System.out.println("消息无法投递:" + new String(message.getBody()));
}
}
🎯 四、消费者(消息监听器)消费 + 手动确认
@Component
publicclass OrderConsumer {
@RabbitListener(queues = "queue.order", ackMode = "MANUAL")
public void onMessage(Message message, Channel channel) throws IOException {
try {
String msg = new String(message.getBody());
System.out.println("收到订单消息:" + msg);
// 处理逻辑成功后手动确认
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
} catch (Exception e) {
// 出错则拒绝消息,可选择重回队列或丢弃
channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
}
}
}
📦 五、消息持久化相关说明
• 交换机持久化:声明时设置 durable = true
• 队列持久化:声明时设置 durable = true
• 消息持久化:发送时设置 deliveryMode = MessageDeliveryMode.PERSISTENT
📌 三者必须同时设置才真正实现消息不丢(即使 RabbitMQ 重启也能恢复)。
队列优先级(Priority Queue) 和 死信队列(Dead Letter Queue,简称 DLQ)
📌 一、优先级队列(Priority Queue)
# 📌 1. 优先级队列(Priority Queue)
RabbitMQ 支持基于消息优先级的队列,即队列中的消息将按照优先级值进行排序,高优先级的消息会被优先消费。
🧠 本质上:RabbitMQ 的优先级队列基于优先级值进行"排序投递",不是严格排序,也不是抢占式消费。
# ✅ 2. 应用场景
• 客服系统中,VIP 用户消息优先处理
• 订单系统中,紧急订单优先处理
• 报警系统中,高等级报警优先发出
# ✅ 3. RabbitMQ 中如何声明优先级队列
优先级范围:默认支持 0~255,默认最大值为 10(需显式声明)
# ✅ 4. Spring 配置
@Bean
public Queue priorityQueue() {
Map<String, Object> args = new HashMap<>();
args.put("x-max-priority", 10); // 最大优先级设为 10
return new Queue("priority.queue", true, false, false, args);
}
# ✅ 5. 发送消息时设置优先级:
rabbitTemplate.convertAndSend("priority.queue", "普通消息",
message -> {
message.getMessageProperties().setPriority(1); // 设置优先级为1
return message;
});
rabbitTemplate.convertAndSend("priority.queue", "高优先级消息",
message -> {
message.getMessageProperties().setPriority(9); // 高优先级
return message;
});
💀 二、死信队列(Dead Letter Queue, DLQ)
# **💀** 1. 死信队列(Dead Letter Queue, DLQ)
死信队列用于处理失败或异常的消息。当一条消息因某种原因无法被正常消费时(如拒绝、过期、队列满),RabbitMQ 会将其转发到死信交换机(Dead Letter Exchange, DLX),再由 DLX 投递到对应的死信队列。
# ✅ 2. 死信的触发条件
• 消费者调用 basicReject() 或 basicNack() 且 requeue = false
• 消息过期(TTL)
• 队列已满(达到最大长度)
# ✅ 3. 使用方式(Spring)
// 步骤一:声明普通队列,并绑定死信交换机
@Bean
public Queue normalQueue() {
Map<String, Object> args = new HashMap<>();
args.put("x-dead-letter-exchange", "dlx.exchange"); // 绑定死信交换机
args.put("x-dead-letter-routing-key", "dlx.key"); // 指定路由 key
args.put("x-message-ttl", 10000); // 消息 10 秒过期(可选)
return new Queue("normal.queue", true, false, false, args);
}
// 步骤二:声明死信交换机和死信队列
@Bean
public DirectExchange dlxExchange() {
return new DirectExchange("dlx.exchange");
}
@Bean
public Queue dlxQueue() {
return new Queue("dead.queue", true);
}
@Bean
public Binding dlxBinding() {
return BindingBuilder.bind(dlxQueue())
.to(dlxExchange())
.with("dlx.key");
}
# ✅ 4. 消费者中拒绝消息(可触发死信)
@RabbitListener(queues = "normal.queue")
public void handle(String msg, Channel channel, Message message) throws IOException {
System.out.println("收到消息:" + msg);
if (msg.contains("错误")) {
// 拒绝消息,不重回队列,消息进入 DLQ
channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
} else {
// 正常确认
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}
}
# 完整流程示意图(文字版)
[发送消息]
↓
[普通交换机] --- routingKey ---→ [普通队列 normal.queue]
↓ 拒绝、过期、满
[死信交换机 dlx.exchange] --- routingKey → [死信队列 dead.queue]
Rabbitmq插件
RabbitMQ 提供了很多强大的 插件(Plugins),可以用来扩展其功能,如:管理界面、消息追踪、限流控制、延迟队列、集群管理等等。
插件名称 | 作用简介 |
---|---|
rabbitmq_management | 提供 Web 管理界面(默认 15672 端口) |
rabbitmq_delayed_message_exchange | 延迟队列实现方式 |
rabbitmq_shovel | 跨实例/数据中心消息复制或转发 |
rabbitmq_federation | 多数据中心消息联邦(类似同步) |
rabbitmq_prometheus | 暴露指标给 Prometheus 监控 |
rabbitmq_auth_backend_ldap | 支持 LDAP 鉴权 |
rabbitmq_web_mqtt | 支持 MQTT 协议通过 WebSocket 接入 |
举例
# ✅ 1. 启用 MQTT 插件
rabbitmq-plugins enable rabbitmq_mqtt
ps: 默认 MQTT 插件监听在端口:1883
# ✅ 2. 修改配置文件(rabbitmq.conf)
配置文件路径取决于安装方式,常见于 /etc/rabbitmq/rabbitmq.conf
添加以下内容:
mqtt.allow_anonymous = true
mqtt.default_user = mqtt
mqtt.default_pass = mqtt
mqtt.vhost = /
mqtt.exchange = amq.topic
# ✅ 3. 添加对应的 RabbitMQ 用户(和权限)
# 添加用户
rabbitmqctl add_user mqtt mqtt
# 设置用户权限(允许操作默认 vhost)
rabbitmqctl set_permissions -p / mqtt ".*" ".*" ".*"
ps: ⚠️ 如果你没创建这个用户,匿名连接时会用默认用户登录,但 RabbitMQ 查不到,会连接失败!
# 连接验证(例如使用 MQTT.fx)
• 主机地址:localhost 或服务器地址
• 端口:1883
• 协议版本:MQTT 3.1 或 3.1.1
• 用户名密码留空
• 连接即可成功
AMQP,STOMP,MQTT 协议
# AMQP(Advanced Message Queuing Protocol)
• 全称:Advanced Message Queuing Protocol(高级消息队列协议)
• 设计目标:企业级消息中间件标准协议
• 主要支持者:RabbitMQ、Apache Qpid、ActiveMQ、Azure Service Bus
• 企业系统间可靠通信(例如银行系统、ERP)
• 电商订单、交易等需要"确保投递"的系统
# STOMP(Simple Text Oriented Messaging Protocol)
• 全称:Simple (or Streaming) Text Oriented Messaging Protocol
• 目标:简化消息系统通信,让客户端更容易接入
• 语法:类 HTTP 协议格式,是基于文本的协议
• 聊天室、在线客服、实时通知系统
• 前后端推送消息(如 Spring WebSocket + STOMP)
# MQTT(Message Queuing Telemetry Transport)
• 设计者:IBM
• 目标:为物联网(IoT)设计的超轻量级协议
• 传输层:基于 TCP/IP,支持 TLS 加密
• 智能家居、智能表计、工业物联网(工业 4.0)
• ESP32、树莓派、Arduino 等设备通信
特性 | AMQP | STOMP | MQTT |
---|---|---|---|
传输层 | TCP | TCP / WebSocket | TCP |
消息模型 | 队列+交换机 | 目的地(destination) | 发布/订阅(topic) |
数据格式 | 二进制 | 文本 | 二进制(紧凑) |
路由功能 | 强(支持多种交换机) | 弱(只有 destination) | 无交换机,使用主题匹配 |
支持离线传输 | 支持(通过持久化) | 一般 | 强(QoS 机制) |
面向对象 | 后端系统(可靠性优先) | 前端浏览器或轻量消息传输 | 物联网设备,嵌入式系统 |
是否适合硬件设备 | 否 | 否 | ✅ 是 |
是否适合浏览器 | 否(不直接支持) | ✅ 是(配合 WebSocket) | 否(需额外桥接) |
RabbitMQ 原生支持 | ✅ 是 | 插件支持 | 插件支持 |
RabbitMQ 如何支持这些协议?
协议 | 插件 | 默认端口 | 说明 |
---|---|---|---|
AMQP | 原生支持 | 5672 | 全功能 |
STOMP | rabbitmq_stomp | 61613 | 文本协议支持 |
STOMP + Web | rabbitmq_web_stomp | 15674 | 浏览器连接 |
MQTT | rabbitmq_mqtt | 1883 | IoT 设备连接 |
MQTT + Web | rabbitmq_web_mqtt | 15675 | 浏览器用 MQTT |
总结
RabbitMQ 与同类产品对比
特性 / 中间件 | RabbitMQ | Kafka | RocketMQ | ActiveMQ | Redis Stream |
---|---|---|---|---|---|
协议支持 | AMQP、MQTT、STOMP、HTTP | 自定义协议 | 自定义 | JMS | Redis 协议 |
消息模型 | 基于队列和交换机(多种路由) | 基于 Topic 分区 | Topic+Tag | Topic+Queue | 基于流结构(Stream) |
消息顺序 | 同一个队列内有序 | 同一个分区内严格有序 | 同分区内顺序 | 顺序控制弱 | 保证插入顺序 |
吞吐量 | 中等(万级) | 极高(百万级) | 高 | 较低 | 中等偏高 |
可靠性 | 高(持久化+ACK) | 非常高(副本机制) | 高 | 一般(依赖配置) | 高(AOF 持久化) |
消息延迟 | 低 | 极低 | 较低 | 较高 | 低 |
消息堆积能力 | 中(基于内存+磁盘) | 极强(磁盘存储) | 强 | 一般 | 一般(依赖内存) |
使用复杂度 | 中(配置灵活) | 高(需要理解架构) | 中偏高 | 简单 | 简单 |
部署运维 | 简单(Erlang) | 复杂(需 ZooKeeper/KRaft) | 中等(Java) | 简单 | 非常简单 |
语言支持 | 多语言(官方/社区) | 多语言(强大生态) | 多语言 | Java为主 | 所有支持 Redis 的语言 |
事务消息 | 弱 | 支持(幂等控制) | 支持事务消息 | 支持但复杂 | 不支持 |
消息过期/延迟 | 支持 TTL/延迟队列 | 需外部组件 | 支持 | 支持 | 支持(Stream 的 ID 控制) |
死信队列支持 | ✅ 支持 | ❌ 不原生支持 | ✅ 支持 | ✅ 支持 | ❌ 不原生支持 |
场景适用度 | 后端解耦、异步任务、IoT | 大数据日志、实时计算、流处理 | 金融、交易系统、事务消息 | 简单异步、老项目 | 简单队列/流计算/缓存场景 |
适用场景对比分析
场景类型 | 推荐中间件 | 理由说明 |
---|---|---|
Web 系统异步任务、接口解耦 | RabbitMQ / ActiveMQ | 多语言支持好,消息路由灵活,易上手 |
高吞吐、日志收集、大数据流 | Kafka | 极高性能,支持海量堆积,分布式处理能力强 |
事务性强的系统(订单/支付) | RocketMQ | 原生支持事务消息,可靠性高 |
IoT 设备通信 | RabbitMQ(MQTT 插件) | 支持 MQTT 协议,兼容多种设备 |
浏览器实时通信(推送) | RabbitMQ(Web STOMP)、Socket.IO | STOMP 插件适合前端 |
简单异步任务、小队列应用 | Redis Stream | 上手快、无需额外组件,轻量级 |
多租户 SaaS 系统 | RabbitMQ / Kafka | RabbitMQ 多 vhost 隔离强,Kafka 多 topic 隔离也可 |
参考资料
rabbitmq: https://www.rabbitmq.com/
rabbitmq下载: https://www.rabbitmq.com/docs/download