RabbitMQ 作为一款高性能的开源消息队列,基于 AMQP(高级消息队列协议)实现,凭借其轻量级、高可用、易扩展的特性,被广泛应用于分布式系统的解耦、异步通信、流量削峰等场景。RabbitMQ 的核心能力体现在多种消息投递模式上,本文作为系列第一篇,将深入解析简单模式(Simple Mode) 和工作队列模式(Work Queue Mode),结合代码实现与场景分析,让你彻底掌握这两种基础模式的使用。
一、前置知识:RabbitMQ 核心概念
在正式讲解模式之前,先快速回顾 RabbitMQ 的几个核心概念,为后续理解铺路:
- 生产者(Producer):发送消息的应用程序。
- 消费者(Consumer):接收并处理消息的应用程序。
- 队列(Queue):消息的存储容器,RabbitMQ 的消息只能存储在队列中,生产者向队列发消息,消费者从队列取消息。
- 交换机(Exchange):在高级模式中负责消息路由,简单模式和工作队列模式中会默认使用内置的默认交换机("")。
- 绑定(Binding):将交换机与队列关联起来的规则,决定消息如何从交换机路由到队列。
二、简单模式(Simple Mode):一对一的消息通信
2.1 模式原理
简单模式是 RabbitMQ 最基础的模式,也被称为点对点模式,其核心架构是一个生产者、一个队列、一个消费者,消息从生产者直接发送到队列,再由唯一的消费者消费。
核心特点:
- 生产者通过默认交换机(名称为空字符串)将消息发送到指定队列,默认交换机是直连交换机,会根据消息的
routing key匹配队列名称进行路由。 - 队列是消息的载体,生产者发送的消息会先存储在队列中,消费者主动从队列拉取消息(或队列推送消息给消费者)。
- 一个队列仅对应一个消费者,消费者消费完消息后,消息会从队列中被移除。
简单模式的架构图如下:
生产者(Producer)→ 队列(Queue)→ 消费者(Consumer)
2.2 代码实现(基于 Java + Spring AMQP)
本文采用 Spring Boot 整合 Spring AMQP 的方式实现,相比原生的 RabbitMQ Client,Spring AMQP 提供了更简洁的 API 和自动配置,开发效率更高。
步骤 1:引入依赖
在pom.xml中添加 Spring Boot 与 RabbitMQ 的整合依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
步骤 2:配置 RabbitMQ 连接
在application.yml中配置 RabbitMQ 的连接信息:
spring:
rabbitmq:
host: localhost # RabbitMQ服务地址
port: 5672 # 默认端口
username: guest # 默认用户名
password: guest # 默认密码
virtual-host: / # 默认虚拟主机
步骤 3:声明队列
创建配置类,声明简单模式使用的队列(队列名称为simple.queue):
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitMQConfig {
/**
* 声明简单模式的队列
* 队列特点:持久化、非排他、非自动删除
*/
@Bean
public Queue simpleQueue() {
return new Queue("simple.queue", true, false, false);
}
}
步骤 4:实现生产者(发送消息)
创建生产者类,通过RabbitTemplate发送消息到队列:
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component
public class SimpleProducer {
@Resource
private RabbitTemplate rabbitTemplate;
/**
* 发送消息到简单队列
* @param message 消息内容
*/
public void sendMessage(String message) {
rabbitTemplate.convertAndSend("simple.queue", message);
System.out.println("简单模式生产者发送消息:" + message);
}
}
步骤 5:实现消费者(接收消息)
创建消费者类,监听队列并处理消息:
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class SimpleConsumer {
/**
* 监听简单队列,消费消息
* @param message 消息内容
*/
@RabbitListener(queues = "simple.queue")
public void consumeMessage(String message) {
System.out.println("简单模式消费者接收消息:" + message);
// 这里可以添加消息处理逻辑,比如业务逻辑调用、数据存储等
}
}
步骤 6:测试代码
创建测试类,调用生产者发送消息:
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
@SpringBootTest
public class SimpleModeTest {
@Resource
private SimpleProducer simpleProducer;
@Test
public void testSendMessage() {
simpleProducer.sendMessage("Hello, RabbitMQ Simple Mode!");
// 休眠1秒,确保消费者有时间处理消息
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行测试后,控制台会输出生产者发送的消息和消费者接收的消息,说明简单模式的消息通信成功。
2.3 场景分析
简单模式适用于一对一的消息通信场景,典型应用场景包括:
- 简单的异步通知:比如用户注册后,发送一封激活邮件,生产者发送注册用户信息到队列,消费者接收后调用邮件发送接口。
- 单一任务的处理:比如后台系统接收到一个数据导入请求,生产者将请求参数发送到队列,消费者接收后执行数据导入操作。
- 日志收集(简单场景):比如小型应用的日志收集,生产者将日志消息发送到队列,消费者接收后将日志写入文件。
注意:简单模式的局限性在于,当消费者处理能力不足时,消息会在队列中堆积,无法通过横向扩展消费者来提高处理效率,这时候就需要用到工作队列模式。
三、工作队列模式(Work Queue Mode):一对多的消息分发
3.1 模式原理
工作队列模式也被称为任务队列模式(Task Queue),其核心架构是一个生产者、一个队列、多个消费者,消息从生产者发送到队列后,由多个消费者竞争消费,每个消息只会被其中一个消费者处理。
核心特点:
- 生产者依然通过默认交换机将消息发送到指定队列,队列存储消息。
- 多个消费者监听同一个队列,RabbitMQ 默认采用轮询(Round-Robin) 策略分发消息,即依次将消息分发给不同的消费者。
- 支持消息确认(ACK)机制,确保消息被消费者处理完成后才从队列中移除,避免消息丢失。
- 可以通过设置消费者的
prefetchCount(预取数量),控制消费者一次获取的消息数量,实现负载均衡。
工作队列模式的架构图如下:
生产者(Producer)→ 队列(Queue)→ 消费者1(Consumer1)
↓
→ 消费者2(Consumer2)
↓
→ 消费者3(Consumer3)
3.2 代码实现(基于 Java + Spring AMQP)
工作队列模式的代码在简单模式的基础上,主要增加多个消费者,并可配置消息确认和预取数量。
步骤 1:复用队列声明(同简单模式)
工作队列模式使用的队列可以复用之前的simple.queue,也可以新建队列(比如work.queue),这里我们新建一个工作队列:
@Configuration
public class RabbitMQConfig {
// 简单模式队列(复用)
@Bean
public Queue simpleQueue() {
return new Queue("simple.queue", true, false, false);
}
/**
* 声明工作队列
*/
@Bean
public Queue workQueue() {
return new Queue("work.queue", true, false, false);
}
}
步骤 2:实现生产者(发送消息)
生产者代码与简单模式类似,只是发送到工作队列:
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component
public class WorkProducer {
@Resource
private RabbitTemplate rabbitTemplate;
/**
* 发送消息到工作队列
* @param message 消息内容
*/
public void sendMessage(String message) {
rabbitTemplate.convertAndSend("work.queue", message);
System.out.println("工作队列模式生产者发送消息:" + message);
}
/**
* 批量发送消息,用于测试多个消费者的分发效果
* @param count 消息数量
*/
public void sendBatchMessage(int count) {
for (int i = 1; i <= count; i++) {
String message = "Work Queue Message " + i;
rabbitTemplate.convertAndSend("work.queue", message);
System.out.println("工作队列模式生产者发送消息:" + message);
}
}
}
步骤 3:实现多个消费者(接收消息)
创建两个消费者,监听同一个工作队列,并模拟不同的处理耗时(体现负载均衡的需求):
消费者 1:
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class WorkConsumer1 {
/**
* 监听工作队列,消费消息(处理耗时较短)
* @param message 消息内容
*/
@RabbitListener(queues = "work.queue")
public void consumeMessage(String message) {
System.out.println("工作队列消费者1接收消息:" + message);
// 模拟处理耗时:100毫秒
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("工作队列消费者1处理完成:" + message);
}
}
消费者 2:
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class WorkConsumer2 {
/**
* 监听工作队列,消费消息(处理耗时较长)
* @param message 消息内容
*/
@RabbitListener(queues = "work.queue")
public void consumeMessage(String message) {
System.out.println("工作队列消费者2接收消息:" + message);
// 模拟处理耗时:500毫秒
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("工作队列消费者2处理完成:" + message);
}
}
步骤 4:配置消息确认和预取数量(优化负载均衡)
默认的轮询策略会忽略消费者的处理能力,导致处理慢的消费者堆积大量消息。我们可以通过配置prefetchCount(预取数量),让消费者一次只获取指定数量的消息,处理完再获取下一批,实现更合理的负载均衡。
在application.yml中添加配置:
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
virtual-host: /
listener:
simple:
acknowledge-mode: manual # 手动确认消息(默认是auto,自动确认)
prefetch: 1 # 预取数量为1,即消费者一次只能处理一条消息,处理完再取
修改消费者代码,添加手动确认消息的逻辑(以消费者 1 为例,消费者 2 同理):
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class WorkConsumer1 {
/**
* 监听工作队列,消费消息(手动确认)
* @param message 消息内容
* @param channel 信道
* @param msg AMQP消息对象
*/
@RabbitListener(queues = "work.queue")
public void consumeMessage(String message, Channel channel, Message msg) throws IOException {
try {
System.out.println("工作队列消费者1接收消息:" + message);
// 模拟处理耗时:100毫秒
Thread.sleep(100);
System.out.println("工作队列消费者1处理完成:" + message);
// 手动确认消息:第二个参数表示是否批量确认
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
} catch (InterruptedException e) {
e.printStackTrace();
// 处理失败时,拒绝消息并重新入队(根据业务需求调整)
channel.basicNack(msg.getMessageProperties().getDeliveryTag(), false, true);
}
}
}
步骤 5:测试代码
创建测试类,批量发送消息,观察多个消费者的消费情况:
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
@SpringBootTest
public class WorkModeTest {
@Resource
private WorkProducer workProducer;
@Test
public void testSendBatchMessage() {
// 批量发送10条消息
workProducer.sendBatchMessage(10);
// 休眠10秒,确保消费者有时间处理所有消息
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行测试后,会发现消费者 1(处理快)会消费更多的消息,而消费者 2(处理慢)消费较少的消息,实现了基于处理能力的负载均衡。
3.3 场景分析
工作队列模式适用于单个队列有大量消息需要处理,且希望通过多个消费者提高处理效率的场景,典型应用场景包括:
- 任务分发:比如电商平台的订单处理,生产者将订单消息发送到队列,多个消费者同时处理订单(如库存扣减、支付确认、物流通知等)。
- 图片处理:用户上传图片后,需要对图片进行压缩、裁剪、水印等处理,生产者将图片信息发送到队列,多个消费者并行处理图片。
- 数据计算:大数据场景下的简单计算任务,生产者将计算任务发送到队列,多个消费者分布式计算,提高计算效率。
- 流量削峰:比如秒杀活动中,大量的下单请求发送到队列,多个消费者慢慢处理,避免系统被瞬间高流量冲垮。
关键优化点:
- 消息持久化:队列和消息都设置为持久化,避免 RabbitMQ 重启后消息丢失。
- 手动消息确认:确保消费者处理完消息后再确认,避免消息丢失。
- 预取数量配置:根据消费者的处理能力设置
prefetchCount,实现负载均衡。 - 消费者限流:通过
prefetchCount限制消费者的并发处理数量,防止消费者过载。
四、简单模式 vs 工作队列模式
为了更清晰地对比两种模式的差异,我们整理了如下表格:
| 特性 | 简单模式 | 工作队列模式 |
|---|---|---|
| 消费者数量 | 一个 | 多个 |
| 消息分发策略 | 单一消费者独占所有消息 | 轮询 / 基于预取的负载均衡 |
| 处理效率 | 低(单消费者) | 高(多消费者并行处理) |
| 适用场景 | 一对一简单通信 | 高并发任务处理、负载均衡 |
| 扩展性 | 差(无法横向扩展消费者) | 好(可动态增加消费者) |
五、总结
本文详细讲解了 RabbitMQ 的两种基础模式:简单模式和工作队列模式。简单模式是一对一的消息通信,适用于简单的异步场景;工作队列模式是一对多的消息分发,通过多个消费者并行处理消息,适用于高并发任务处理场景。
在实际开发中,需要根据业务场景选择合适的模式:如果是简单的异步通知,使用简单模式即可;如果是大量任务需要处理,建议使用工作队列模式,并结合消息持久化、手动确认、预取数量配置等优化手段,确保消息处理的可靠性和效率。
下一篇文章,我们将继续讲解 RabbitMQ 的另外三种核心模式:发布 / 订阅模式、路由模式和主题模式,敬请期待!


被折叠的 条评论
为什么被折叠?



