RabbitMQ全面实战:交换机、队列、场景落地与源码实现
在分布式系统中,消息中间件是实现异步通信、解耦服务、削峰填谷的核心组件。而 RabbitMQ 作为基于 AMQP(高级消息队列协议)的开源消息中间件,凭借其灵活的路由机制、可靠的消息投递、丰富的功能特性,成为企业级应用的首选。本文将从核心概念出发,详细拆解 RabbitMQ 的多种交换机、队列类型,结合实际业务场景提供解决方案,并附上可直接复用的 SpringBoot 整合源码,助力开发者快速上手并落地生产。
一、RabbitMQ 核心价值与核心概念
1.1 为什么选择 RabbitMQ?
- 异步解耦:打破服务间同步依赖,比如订单系统无需等待支付系统响应即可完成下单,通过消息异步通知后续流程;
- 削峰填谷:应对高并发场景(如秒杀、促销),将突发流量缓存到队列,消费者按能力平滑处理,避免服务雪崩;
- 可靠投递:支持消息持久化、生产者确认、消费者 ACK、死信队列等机制,确保消息不丢失、不重复;
- 灵活路由:通过多种交换机实现复杂路由规则,满足广播、精准匹配、模糊匹配等不同需求;
- 多语言支持:兼容 Java、Python、Go 等多种语言,适配异构系统集成。
1.2 核心概念速通
在深入实战前,需先掌握 5 个核心概念,理解消息流转链路:
- 生产者(Producer) :发送消息的应用程序;
- 消费者(Consumer) :接收并处理消息的应用程序;
- 交换机(Exchange) :接收生产者消息,根据路由规则将消息路由到绑定的队列(核心路由组件,不存储消息);
- 队列(Queue) :存储消息的容器,与消费者绑定,按顺序投递消息;
- 绑定(Binding) :将交换机与队列关联,同时指定「绑定键(Binding Key)」,交换机根据「路由键(Routing Key)」与绑定键的匹配规则路由消息;
- 虚拟主机(Virtual Host) :隔离不同环境的资源(如开发、测试),每个虚拟主机有独立的交换机、队列、用户权限。
消息流转链路:生产者 → 交换机(按路由规则)→ 绑定的队列 → 消费者
二、RabbitMQ 四大核心交换机:特点、场景与源码
交换机是 RabbitMQ 路由机制的核心,不同交换机对应不同路由策略。以下详解四种常用交换机的使用场景与实战源码(基于 SpringBoot 2.7.x)。
2.1 Direct 交换机:精准路由(一对一匹配)
核心特点
- 路由规则:消息的「路由键(Routing Key)」必须与队列的「绑定键(Binding Key)」完全一致,才会路由到对应队列;
- 本质:一对一或多对一(多个队列绑定同一绑定键)的精准匹配。
适用场景
- 单一目标路由:如订单支付成功后,仅通知订单系统更新状态;
- 任务分发:将特定任务分配给指定消费者处理(如不同类型的任务路由到不同消费者队列)。
实战源码
1. 依赖配置(pom.xml)
<!-- RabbitMQ 核心依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
2. 配置文件(application.yml)
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
virtual-host: /
publisher-confirm-type: correlated # 生产者确认
publisher-returns: true # 消息返回回调
listener:
simple:
acknowledge-mode: manual # 手动ACK
concurrency: 3
max-concurrency: 5
3. 交换机与队列配置
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DirectExchangeConfig {
// 交换机名称
public static final String DIRECT_EXCHANGE_NAME = "direct_order_exchange";
// 订单状态更新队列
public static final String ORDER_STATUS_QUEUE = "order_status_queue";
// 支付通知队列
public static final String PAY_NOTIFY_QUEUE = "pay_notify_queue";
// 绑定键
public static final String ORDER_STATUS_ROUTING_KEY = "order.status.update";
public static final String PAY_NOTIFY_ROUTING_KEY = "pay.notify.send";
// 1. 声明 Direct 交换机
@Bean
public DirectExchange directOrderExchange() {
// durable: 持久化;autoDelete: 无绑定后自动删除;internal: 是否内部交换机(一般为false)
return ExchangeBuilder.directExchange(DIRECT_EXCHANGE_NAME)
.durable(true)
.autoDelete(false)
.internal(false)
.build();
}
// 2. 声明队列
@Bean
public Queue orderStatusQueue() {
// durable: 持久化;exclusive: 排他队列(仅当前连接可用);autoDelete: 无消费者后自动删除
return QueueBuilder.durable(ORDER_STATUS_QUEUE)
.exclusive(false)
.autoDelete(false)
.build();
}
@Bean
public Queue payNotifyQueue() {
return QueueBuilder.durable(PAY_NOTIFY_QUEUE)
.exclusive(false)
.autoDelete(false)
.build();
}
// 3. 绑定交换机与队列(指定绑定键)
@Bean
public Binding orderStatusBinding() {
return BindingBuilder.bind(orderStatusQueue())
.to(directOrderExchange())
.with(ORDER_STATUS_ROUTING_KEY);
}
@Bean
public Binding payNotifyBinding() {
return BindingBuilder.bind(payNotifyQueue())
.to(directOrderExchange())
.with(PAY_NOTIFY_ROUTING_KEY);
}
}
4. 生产者(消息发送)
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
@Service
@Slf4j
@RequiredArgsConstructor
public class DirectProducer {
private final RabbitTemplate rabbitTemplate;
/**
* 发送订单状态更新消息
*/
public void sendOrderStatusMessage(Long orderId, String status) {
String message = String.format("订单[%s]状态更新为:%s", orderId, status);
// 发送消息:交换机名称 + 路由键 + 消息内容
rabbitTemplate.convertAndSend(
DirectExchangeConfig.DIRECT_EXCHANGE_NAME,
DirectExchangeConfig.ORDER_STATUS_ROUTING_KEY,
message,
correlationData -> {
correlationData.setId(orderId.toString()); // 关联ID(用于生产者确认)
return correlationData;
}
);
log.info("Direct交换机发送订单状态消息成功:{}", message);
}
/**
* 发送支付通知消息
*/
public void sendPayNotifyMessage(Long orderId, String payType) {
String message = String.format("订单[%s]通过%s支付成功,已发送通知", orderId, payType);
rabbitTemplate.convertAndSend(
DirectExchangeConfig.DIRECT_EXCHANGE_NAME,
DirectExchangeConfig.PAY_NOTIFY_ROUTING_KEY,
message,
correlationData -> {
correlationData.setId(orderId.toString());
return correlationData;
}
);
log.info("Direct交换机发送支付通知消息成功:{}", message);
}
}
5. 消费者(消息接收)
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;
import com.rabbitmq.client.Channel;
@Component
@Slf4j
public class DirectConsumer {
/**
* 消费订单状态更新消息
*/
@RabbitListener(queues = DirectExchangeConfig.ORDER_STATUS_QUEUE)
public void consumeOrderStatusMessage(String message, Channel channel,
@Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) throws Exception {
try {
log.info("接收订单状态消息:{}", message);
// 模拟业务处理:更新订单状态到数据库
// orderService.updateStatus(orderId, status);
channel.basicAck(deliveryTag, false); // 手动ACK确认消费成功
} catch (Exception e) {
log.error("消费订单状态消息失败", e);
// 消费失败,重新入队(最多重试3次,可结合死信队列优化)
channel.basicNack(deliveryTag, false, true);
}
}
/**
* 消费支付通知消息
*/
@RabbitListener(queues = DirectExchangeConfig.PAY_NOTIFY_QUEUE)
public void consumePayNotifyMessage(String message, Channel channel,
@Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) throws Exception {
try {
log.info("接收支付通知消息:{}", message);
// 模拟业务处理:发送短信/邮件通知用户
// notifyService.sendSms(message);
channel.basicAck(deliveryTag, false);
} catch (Exception e) {
log.error("消费支付通知消息失败", e);
channel.basicNack(deliveryTag, false, true);
}
}
}
6. 测试接口
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequiredArgsConstructor
public class DirectTestController {
private final DirectProducer directProducer;
@GetMapping("/direct/sendOrderStatus")
public String sendOrderStatus(@RequestParam Long orderId, @RequestParam String status) {
directProducer.sendOrderStatusMessage(orderId, status);
return "订单状态消息发送成功";
}
@GetMapping("/direct/sendPayNotify")
public String sendPayNotify(@RequestParam Long orderId, @RequestParam String payType) {
directProducer.sendPayNotifyMessage(orderId, payType);
return "支付通知消息发送成功";
}
}
2.2 Topic 交换机:模糊路由(多条件匹配)
核心特点
- 路由规则:支持通配符匹配,路由键和绑定键采用「.」分隔的多级结构(如
order.status.paid); - 通配符:
*匹配单个层级,#匹配零个或多个层级(如绑定键order.#可匹配order.status、order.status.paid); - 本质:多对多的模糊匹配,灵活性最高。
适用场景
- 多级分类路由:如商品消息按「品类。操作」路由(
electronics.add、clothes.update); - 批量通知:如通知某类用户的所有子系统(
user.#匹配用户相关的所有消息); - 日志分级路由:如日志按「系统。级别」路由(
order.info、pay.error)。
实战源码
1. 交换机与队列配置
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class TopicExchangeConfig {
// 交换机名称
public static final String TOPIC_EXCHANGE_NAME = "topic_log_exchange";
// 订单日志队列(匹配order相关所有日志)
public static final String ORDER_LOG_QUEUE = "order_log_queue";
// 支付错误日志队列(仅匹配pay的error日志)
public static final String PAY_ERROR_LOG_QUEUE = "pay_error_log_queue";
// 绑定键
public static final String ORDER_LOG_ROUTING_KEY = "order.#"; // 匹配order开头的所有路由键
public static final String PAY_ERROR_LOG_ROUTING_KEY = "pay.*.error"; // 匹配pay.xxx.error
// 1. 声明 Topic 交换机
@Bean
public TopicExchange topicLogExchange() {
return ExchangeBuilder.topicExchange(TOPIC_EXCHANGE_NAME)
.durable(true)
.autoDelete(false)
.build();
}
// 2. 声明队列
@Bean
public Queue orderLogQueue() {
return QueueBuilder.durable(ORDER_LOG_QUEUE).build();
}
@Bean
public Queue payErrorLogQueue() {
return QueueBuilder.durable(PAY_ERROR_LOG_QUEUE).build();
}
// 3. 绑定
@Bean
public Binding orderLogBinding() {
return BindingBuilder.bind(orderLogQueue()).to(topicLogExchange()).with(ORDER_LOG_ROUTING_KEY);
}
@Bean
public Binding payErrorLogBinding() {
return BindingBuilder.bind(payErrorLogQueue()).to(topicLogExchange()).with(PAY_ERROR_LOG_ROUTING_KEY);
}
}
2. 生产者
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
@Service
@Slf4j
@RequiredArgsConstructor
public class TopicProducer {
private final RabbitTemplate rabbitTemplate;
/**
* 发送日志消息
* @param routingKey 路由键(如order.info、pay.system.error)
* @param logContent 日志内容
*/
public void sendLog(String routingKey, String logContent) {
rabbitTemplate.convertAndSend(
TopicExchangeConfig.TOPIC_EXCHANGE_NAME,
routingKey,
logContent,
correlationData -> {
correlationData.setId(System.currentTimeMillis() + "");
return correlationData;
}
);
log.info("Topic交换机发送日志消息:routingKey={}, content={}", routingKey, logContent);
}
}
3. 消费者
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;
import com.rabbitmq.client.Channel;
@Component
@Slf4j
public class TopicConsumer {
/**
* 消费订单相关所有日志
*/
@RabbitListener(queues = TopicExchangeConfig.ORDER_LOG_QUEUE)
public void consumeOrderLog(String message, Channel channel,
@Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) throws Exception {
try {
log.info("【订单日志】接收消息:{}", message);
// 模拟业务:存储订单日志到数据库
channel.basicAck(deliveryTag, false);
} catch (Exception e) {
log.error("消费订单日志失败", e);
channel.basicNack(deliveryTag, false, false); // 失败不重新入队,后续可结合死信队列
}
}
/**
* 消费支付错误日志
*/
@RabbitListener(queues = TopicExchangeConfig.PAY_ERROR_LOG_QUEUE)
public void consumePayErrorLog(String message, Channel channel,
@Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) throws Exception {
try {
log.info("【支付错误日志】接收消息:{}", message);
// 模拟业务:发送告警通知运维人员
channel.basicAck(deliveryTag, false);
} catch (Exception e) {
log.error("消费支付错误日志失败", e);
channel.basicNack(deliveryTag, false, false);
}
}
}
4. 测试接口
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequiredArgsConstructor
public class TopicTestController {
private final TopicProducer topicProducer;
@GetMapping("/topic/sendLog")
public String sendLog(@RequestParam String routingKey, @RequestParam String logContent) {
topicProducer.sendLog(routingKey, logContent);
return "日志消息发送成功";
}
}
2.3 Fanout 交换机:广播路由(无差别分发)
核心特点
- 路由规则:忽略路由键和绑定键,将消息广播到所有与该交换机绑定的队列;
- 本质:一对多的无差别分发,消息发送效率最高(无需路由匹配)。
适用场景
- 系统公告:如平台发布全局通知,所有服务都需接收;
- 数据同步:如用户信息更新后,同步到缓存、搜索、统计等多个子系统;
- 日志收集:如将应用日志同时发送到日志存储、监控告警、实时分析等队列。
实战源码
1. 交换机与队列配置
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FanoutExchangeConfig {
// 交换机名称
public static final String FANOUT_EXCHANGE_NAME = "fanout_notice_exchange";
// 缓存同步队列
public static final String CACHE_SYNC_QUEUE = "cache_sync_queue";
// 搜索同步队列
public static final String SEARCH_SYNC_QUEUE = "search_sync_queue";
// 统计同步队列
public static final String STATISTICS_SYNC_QUEUE = "statistics_sync_queue";
// 1. 声明 Fanout 交换机
@Bean
public FanoutExchange fanoutNoticeExchange() {
return ExchangeBuilder.fanoutExchange(FANOUT_EXCHANGE_NAME)
.durable(true)
.autoDelete(false)
.build();
}
// 2. 声明队列
@Bean
public Queue cacheSyncQueue() {
return QueueBuilder.durable(CACHE_SYNC_QUEUE).build();
}
@Bean
public Queue searchSyncQueue() {
return QueueBuilder.durable(SEARCH_SYNC_QUEUE).build();
}
@Bean
public Queue statisticsSyncQueue() {
return QueueBuilder.durable(STATISTICS_SYNC_QUEUE).build();
}
// 3. 绑定(Fanout交换机无需指定绑定键)
@Bean
public Binding cacheSyncBinding() {
return BindingBuilder.bind(cacheSyncQueue()).to(fanoutNoticeExchange());
}
@Bean
public Binding searchSyncBinding() {
return BindingBuilder.bind(searchSyncQueue()).to(fanoutNoticeExchange());
}
@Bean
public Binding statisticsSyncBinding() {
return BindingBuilder.bind(statisticsSyncQueue()).to(fanoutNoticeExchange());
}
}
2. 生产者
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
@Service
@Slf4j
@RequiredArgsConstructor
public class FanoutProducer {
private final RabbitTemplate rabbitTemplate;
/**
* 发送用户信息同步通知(广播到所有绑定队列)
*/
public void sendUserSyncNotice(Long userId, String userName) {
String message = String.format("用户信息更新:userId=%s, userName=%s", userId, userName);
// Fanout交换机无需指定路由键(传空字符串即可)
rabbitTemplate.convertAndSend(
FanoutExchangeConfig.FANOUT_EXCHANGE_NAME,
"",
message,
correlationData -> {
correlationData.setId(userId.toString());
return correlationData;
}
);
log.info("Fanout交换机发送用户同步通知:{}", message);
}
}
3. 消费者
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;
import com.rabbitmq.client.Channel;
@Component
@Slf4j
public class FanoutConsumer {
/**
* 缓存同步消费
*/
@RabbitListener(queues = FanoutExchangeConfig.CACHE_SYNC_QUEUE)
public void consumeCacheSync(String message, Channel channel,
@Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) throws Exception {
try {
log.info("【缓存同步】接收消息:{}", message);
// 模拟业务:更新Redis缓存中的用户信息
// redisService.set("user:" + userId, userInfo);
channel.basicAck(deliveryTag, false);
} catch (Exception e) {
log.error("缓存同步失败", e);
channel.basicNack(deliveryTag, false, true);
}
}
/**
* 搜索同步消费
*/
@RabbitListener(queues = FanoutExchangeConfig.SEARCH_SYNC_QUEUE)
public void consumeSearchSync(String message, Channel channel,
@Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) throws Exception {
try {
log.info("【搜索同步】接收消息:{}", message);
// 模拟业务:更新Elasticsearch中的用户索引
// esService.updateUserIndex(userId, userInfo);
channel.basicAck(deliveryTag, false);
} catch (Exception e) {
log.error("搜索同步失败", e);
channel.basicNack(deliveryTag, false, true);
}
}
/**
* 统计同步消费
*/
@RabbitListener(queues = FanoutExchangeConfig.STATISTICS_SYNC_QUEUE)
public void consumeStatisticsSync(String message, Channel channel,
@Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) throws Exception {
try {
log.info("【统计同步】接收消息:{}", message);
// 模拟业务:更新用户统计数据
// statisticsService.updateUserStat(userId);
channel.basicAck(deliveryTag, false);
} catch (Exception e) {
log.error("统计同步失败", e);
channel.basicNack(deliveryTag, false, true);
}
}
}
4. 测试接口
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequiredArgsConstructor
public class FanoutTestController {
private final FanoutProducer fanoutProducer;
@GetMapping("/fanout/sendUserSync")
public String sendUserSync(@RequestParam Long userId, @RequestParam String userName) {
fanoutProducer.sendUserSyncNotice(userId, userName);
return "用户同步通知发送成功(所有绑定队列均会接收)";
}
}
2.4 Headers 交换机:属性路由(非路由键匹配)
核心特点
- 路由规则:忽略路由键,根据消息的「headers 属性」匹配队列的绑定条件(如
x-match=all表示所有属性都匹配,x-match=any表示任意一个属性匹配); - 适用场景:消息路由条件不适合用路由键表示的场景(如多维度属性匹配),但实际使用频率低于前三种交换机。
适用场景
- 多维度过滤:如根据「地区 = 北京」「终端 = APP」「版本 = V2」等多个属性路由消息;
- 复杂条件路由:路由规则无法通过简单的路由键通配符表达的场景。
实战源码
1. 交换机与队列配置
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class HeadersExchangeConfig {
// 交换机名称
public static final String HEADERS_EXCHANGE_NAME = "headers_filter_exchange";
// APP终端队列(匹配地区=北京且终端=APP)
public static final String APP_QUEUE = "app_queue";
// Web终端队列(匹配地区=上海或终端=Web)
public static final String WEB_QUEUE = "web_queue";
// 1. 声明 Headers 交换机
@Bean
public HeadersExchange headersFilterExchange() {
return ExchangeBuilder.headersExchange(HEADERS_EXCHANGE_NAME)
.durable(true)
.autoDelete(false)
.build();
}
// 2. 声明队列
@Bean
public Queue appQueue() {
return QueueBuilder.durable(APP_QUEUE).build();
}
@Bean
public Queue webQueue() {
return QueueBuilder.durable(WEB_QUEUE).build();
}
// 3. 绑定:APP队列(x-match=all,所有属性都匹配)
@Bean
public Binding appBinding() {
Map<String, Object> headers = new HashMap<>();
headers.put("region", "Beijing"); // 地区=北京
headers.put("terminal", "APP"); // 终端=APP
return BindingBuilder.bind(appQueue())
.to(headersFilterExchange())
.whereAll(headers).match(); // 所有属性匹配
}
// 4. 绑定:Web队列(x-match=any,任意属性匹配)
@Bean
public Binding webBinding() {
Map<String, Object> headers = new HashMap<>();
headers.put("region", "Shanghai"); // 地区=上海
headers.put("terminal", "Web"); // 终端=Web
return BindingBuilder.bind(webQueue())
.to(headersFilterExchange())
.whereAny(headers).match(); // 任意属性匹配
}
}
2. 生产者
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
@Service
@Slf4j
@RequiredArgsConstructor
public class HeadersProducer {
private final RabbitTemplate rabbitTemplate;
/**
* 发送带Headers属性的消息
*/
public void sendHeadersMessage(String content, String region, String terminal) {
// 设置消息Headers属性
MessageProperties properties = new MessageProperties();
properties.setHeader("region", region);
properties.setHeader("terminal", terminal);
Message message = new Message(content.getBytes(), properties);
// Headers交换机无需指定路由键
rabbitTemplate.convertAndSend(
HeadersExchangeConfig.HEADERS_EXCHANGE_NAME,
"",
message,
correlationData -> {
correlationData.setId(System.currentTimeMillis() + "");
return correlationData;
}
);
log.info("Headers交换机发送消息:content={}, region={}, terminal={}", content, region, terminal);
}
}
3. 消费者
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;
import com.rabbitmq.client.Channel;
@Component
@Slf4j
public class HeadersConsumer {
/**
* 消费APP队列消息
*/
@RabbitListener(queues = HeadersExchangeConfig.APP_QUEUE)
public void consumeAppQueue(Message message, Channel channel,
@Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) throws Exception {
try {
String content = new String(message.getBody());
String region = (String) message.getMessageProperties().getHeader("region");
String terminal = (String) message.getMessageProperties().getHeader("terminal");
log.info("【APP队列】接收消息:content={}, region={}, terminal={}", content, region, terminal);
channel.basicAck(deliveryTag, false);
} catch (Exception e) {
log.error("消费APP队列消息失败", e);
channel.basicNack(deliveryTag, false, true);
}
}
/**
* 消费Web队列消息
*/
@RabbitListener(queues = HeadersExchangeConfig.WEB_QUEUE)
public void consumeWebQueue(Message message, Channel channel,
@Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) throws Exception {
try {
String content = new String(message.getBody());
String region = (String) message.getMessageProperties().getHeader("region");
String terminal = (String) message.getMessageProperties().getHeader("terminal");
log.info("【Web队列】接收消息:content={}, region={}, terminal={}", content, region, terminal);
channel.basicAck(deliveryTag, false);
} catch (Exception e) {
log.error("消费Web队列消息失败", e);
channel.basicNack(deliveryTag, false, true);
}
}
}
4. 测试接口
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequiredArgsConstructor
public class HeadersTestController {
private final HeadersProducer headersProducer;
@GetMapping("/headers/sendMessage")
public String sendMessage(@RequestParam String content,
@RequestParam String region,
@RequestParam String terminal) {
headersProducer.sendHeadersMessage(content, region, terminal);
return "Headers消息发送成功";
}
}
三、RabbitMQ 常用队列类型:场景与实现
除了基础队列,RabbitMQ 提供了多种特殊队列,满足复杂业务需求。以下介绍四种核心队列的使用场景与源码实现。
3.1 死信队列(DLX):失败消息处理
核心概念
- 死信:无法被消费的消息(如消费重试次数耗尽、消息过期、队列达到最大长度);
- 死信队列:存储死信的队列,需通过「死信交换机(DLX)」路由死信;
- 核心价值:避免失败消息丢失,便于后续排查问题或人工重试。
适用场景
- 订单支付超时未支付(消息过期后进入死信队列,触发订单关闭);
- 消费失败的消息(重试 3 次后进入死信队列,避免重复重试占用资源);
- 队列满了无法接收新消息(超出长度的消息进入死信队列,避免消息丢失)。
实战源码(基于 Direct 交换机实现)
1. 配置类
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DeadLetterQueueConfig {
// 普通交换机
public static final String NORMAL_EXCHANGE_NAME = "normal_order_exchange";
// 死信交换机
public static final String DLX_EXCHANGE_NAME = "dlx_order_exchange";
// 普通队列(订单支付队列)
public static final String NORMAL_QUEUE_NAME = "normal_order_queue";
// 死信队列(订单关闭队列)
public static final String DLX_QUEUE_NAME = "dlx_order_queue";
// 绑定键
public static final String NORMAL_ROUTING_KEY = "order.pay";
public static final String DLX_ROUTING_KEY = "order.dlx";
// 1. 声明死信交换机(Direct类型)
@Bean
public DirectExchange dlxOrderExchange() {
return ExchangeBuilder.directExchange(DLX_EXCHANGE_NAME).durable(true).build();
}
// 2. 声明死信队列
@Bean
public Queue dlxOrderQueue() {
return QueueBuilder.durable(DLX_QUEUE_NAME).build();
}
// 3. 绑定死信交换机与死信队列
@Bean
public Binding dlxBinding() {
return BindingBuilder.bind(dlxOrderQueue()).to(dlxOrderExchange()).with(DLX_ROUTING_KEY);
}
// 4. 声明普通队列(配置死信相关参数)
@Bean
public Queue normalOrderQueue() {
return QueueBuilder.durable(NORMAL_QUEUE_NAME)
.withArgument("x-dead-letter-exchange", DLX_EXCHANGE_NAME) // 绑定死信交换机
.withArgument("x-dead-letter-routing-key", DLX_ROUTING_KEY) // 死信路由键
.withArgument("x-message-ttl", 60000) // 消息过期时间(1分钟)
.withArgument("x-max-length", 1000) // 队列最大长度(1000条)
.build();
}
// 5. 声明普通交换机
@Bean
public DirectExchange normalOrderExchange() {
return ExchangeBuilder.directExchange(NORMAL_EXCHANGE_NAME).durable(true).build();
}
// 6. 绑定普通交换机与普通队列
@Bean
public Binding normalBinding() {
return BindingBuilder.bind(normalOrderQueue()).to(normalOrderExchange()).with(NORMAL_ROUTING_KEY);
}
}
2. 生产者(发送订单支付消息)
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
@Service
@Slf4j
@RequiredArgsConstructor
public class DlxProducer {
private final RabbitTemplate rabbitTemplate;
public void sendOrderPayMessage(Long orderId) {
String message = String.format("订单[%s]待支付,1分钟内未支付将自动关闭", orderId);
rabbitTemplate.convertAndSend(
DeadLetterQueueConfig.NORMAL_EXCHANGE_NAME,
DeadLetterQueueConfig.NORMAL_ROUTING_KEY,
message,
correlationData -> {
correlationData.setId(orderId.toString());
return correlationData;
}
);
log.info("发送订单支付消息:{}", message);
}
}
3. 消费者(普通队列消费 + 死信队列消费)
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;
import com.rabbitmq.client.Channel;
@Component
@Slf4j
public class DlxConsumer {
// 重试次数上限
private static final int MAX_RETRY_COUNT = 3;
/**
* 消费普通队列(订单支付消息)
*/
@RabbitListener(queues = DeadLetterQueueConfig.NORMAL_QUEUE_NAME)
public void consumeNormalQueue(String message, Channel channel,
@Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag,
@Header(AmqpHeaders.REDELIVERED) boolean redelivered) throws Exception {
// 解析订单ID(实际业务中可通过消息体传递)
String orderId = message.split("\[")[1].split("\]")[0];
int retryCount = redelivered ? 1 : 0; // 重试次数(redelivered为true表示重新入队)
try {
log.info("接收订单支付消息:{},重试次数:{}", message, retryCount);
// 模拟业务:查询订单支付状态
// boolean isPaid = orderService.checkPayStatus(Long.parseLong(orderId));
// if (isPaid) {
// channel.basicAck(deliveryTag, false); // 已支付,确认消费
// } else {
// throw new RuntimeException("订单未支付,需要重试");
// }
// 模拟消费失败(实际业务中根据支付状态判断)
throw new RuntimeException("订单未支付");
} catch (Exception e) {
log.error("消费订单支付消息失败", e);
if (retryCount >= MAX_RETRY_COUNT) {
// 重试次数耗尽,拒绝消息,进入死信队列
log.info("重试次数耗尽,消息进入死信队列:{}", message);
channel.basicReject(deliveryTag, false);
} else {
// 重新入队,重试
channel.basicNack(deliveryTag, false, true);
}
}
}
/**
* 消费死信队列(订单关闭消息)
*/
@RabbitListener(queues = DeadLetterQueueConfig.DLX_QUEUE_NAME)
public void consumeDlxQueue(String message, Channel channel,
@Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) throws Exception {
try {
log.info("接收死信消息,执行订单关闭:{}", message);
// 模拟业务:关闭订单、释放库存
// orderService.closeOrder(Long.parseLong(orderId));
channel.basicAck(deliveryTag, false);
} catch (Exception e) {
log.error("处理死信消息失败", e);
channel.basicAck(deliveryTag, false); // 死信队列消息不再重试,避免死循环
}
}
}
3.2 延迟队列:定时任务实现
核心概念
-
延迟队列:消息发送后,延迟指定时间才被消费的队列;
-
实现方式:
- TTL + 死信队列(基于 RabbitMQ 原生功能,适用于延迟时间固定的场景);
- 延迟交换机插件(rabbitmq-delayed-message-exchange,支持动态延迟时间,推荐生产使用)。
适用场景
- 订单超时关闭(延迟 30 分钟);
- 定时通知(如会议开始前 10 分钟提醒);
- 任务重试(延迟 5 分钟后重试失败任务)。
实战源码(基于延迟插件实现)
1. 安装延迟插件
- 下载插件:从 RabbitMQ 官方插件库 下载
rabbitmq_delayed_message_exchange插件; - 安装插件:将插件复制到 RabbitMQ 插件目录(如
/usr/lib/rabbitmq/lib/rabbitmq_server-3.12.0/plugins),执行命令rabbitmq-plugins enable rabbitmq_delayed_message_exchange; - 重启 RabbitMQ:
systemctl restart rabbitmq-server。
2. 配置类
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DelayedQueueConfig {
// 延迟交换机名称
public static final String DELAYED_EXCHANGE_NAME = "delayed_notice_exchange";
// 延迟队列名称
public static final String DELAYED_QUEUE_NAME = "delayed_notice_queue";
// 绑定键
public static final String DELAYED_ROUTING_KEY = "notice.delayed";
// 1. 声明延迟交换机(类型为 x-delayed-message)
@Bean
public CustomExchange delayedNoticeExchange() {
// 配置交换机类型和延迟参数
return new CustomExchange(
DELAYED_EXCHANGE_NAME,
"x-delayed-message", // 延迟交换机类型
true, // 持久化
false, // 自动删除
Map.of("x-delayed-type", "direct") // 延迟交换机的路由类型(Direct/Topic等)
);
}
// 2. 声明延迟队列
@Bean
public Queue delayedNoticeQueue() {
return QueueBuilder.durable(DELAYED_QUEUE_NAME).build();
}
// 3. 绑定延迟交换机与队列
@Bean
public Binding delayedBinding() {
return BindingBuilder.bind(delayedNoticeQueue())
.to(delayedNoticeExchange())
.with(DELAYED_ROUTING_KEY)
.noargs();
}
}
3. 生产者
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
@Service
@Slf4j
@RequiredArgsConstructor
public class DelayedProducer {
private final RabbitTemplate rabbitTemplate;
/**
* 发送延迟消息
* @param content 消息内容
* @param delayTime 延迟时间(毫秒)
*/
public void sendDelayedMessage(String content, long delayTime) {
rabbitTemplate.convertAndSend(
DelayedQueueConfig.DELAYED_EXCHANGE_NAME,
DelayedQueueConfig.DELAYED_ROUTING_KEY,
content,
new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message) throws AmqpException {
// 设置延迟时间(核心)
message.getMessageProperties().setHeader("x-delay", delayTime);
return message;
}
},
correlationData -> {
correlationData.setId(System.currentTimeMillis() + "");
return correlationData;
}
);
log.info("发送延迟消息:content={}, 延迟时间={}ms", content, delayTime);
}
}
4. 消费者
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;
import com.rabbitmq.client.Channel;
@Component
@Slf4j
public class DelayedConsumer {
@RabbitListener(queues = DelayedQueueConfig.DELAYED_QUEUE_NAME)
public void consumeDelayedQueue(String message, Channel channel,
@Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) throws Exception {
try {
log.info("延迟消息到期,接收消息:{}", message);
// 模拟业务:发送定时通知
// notifyService.sendReminder(message);
channel.basicAck(deliveryTag, false);
} catch (Exception e) {
log.error("消费延迟消息失败", e);
channel.basicNack(deliveryTag, false, false);
}
}
}
5. 测试接口
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequiredArgsConstructor
public class DelayedTestController {
private final DelayedProducer delayedProducer;
@GetMapping("/delayed/sendMessage")
public String sendMessage(@RequestParam String content, @RequestParam long delayTime) {
delayedProducer.sendDelayedMessage(content, delayTime);
return "延迟消息发送成功";
}
}
3.3 优先级队列:消息优先级排序
核心概念
- 优先级队列:支持为消息设置优先级(0-255,数值越大优先级越高),消费者优先消费高优先级消息;
- 核心价值:确保重要消息被优先处理(如 VIP 用户的订单、紧急告警)。
适用场景
- 订单优先级:VIP 用户的订单优先处理;
- 告警优先级:严重告警(P0 级)优先于普通告警(P3 级);
- 任务优先级:紧急任务(如数据修复)优先于普通任务(如数据统计)。
实战源码
1. 配置类
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class PriorityQueueConfig {
// 交换机名称
public static final String PRIORITY_EXCHANGE_NAME = "priority_order_exchange";
// 优先级队列名称
public static final String PRIORITY_QUEUE_NAME = "priority_order_queue";
// 绑定键
public static final String PRIORITY_ROUTING_KEY = "order.priority";
// 1. 声明交换机(Direct类型)
@Bean
public DirectExchange priorityOrderExchange() {
return ExchangeBuilder.directExchange(PRIORITY_EXCHANGE_NAME).durable(true).build();
}
// 2. 声明优先级队列(设置最大优先级)
@Bean
public Queue priorityOrderQueue() {
return QueueBuilder.durable(PRIORITY_QUEUE_NAME)
.withArgument("x-max-priority", 10) // 最大优先级(0-10,数值越大优先级越高)
.build();
}
// 3. 绑定
@Bean
public Binding priorityBinding() {
return BindingBuilder.bind(priorityOrderQueue()).to(priorityOrderExchange()).with(PRIORITY_ROUTING_KEY);
}
}
2. 生产者
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
@Service
@Slf4j
@RequiredArgsConstructor
public class PriorityProducer {
private final RabbitTemplate rabbitTemplate;
/**
* 发送带优先级的订单消息
* @param orderId 订单ID
* @param userType 用户类型(VIP/NORMAL)
* @param priority 优先级(1-10)
*/
public void sendPriorityOrderMessage(Long orderId, String userType, int priority) {
String message = String.format("用户类型:%s,订单[%s]待处理", userType, orderId);
rabbitTemplate.convertAndSend(
PriorityQueueConfig.PRIORITY_EXCHANGE_NAME,
PriorityQueueConfig.PRIORITY_ROUTING_KEY,
message,
new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message) throws AmqpException {
// 设置消息优先级
message.getMessageProperties().setPriority(priority);
return message;
}
},
correlationData -> {
correlationData.setId(orderId.toString());
return correlationData;
}
);
log.info("发送优先级订单消息:content={}, 优先级={}", message, priority);
}
}
3. 消费者
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;
import com.rabbitmq.client.Channel;
@Component
@Slf4j
public class PriorityConsumer {
@RabbitListener(queues = PriorityQueueConfig.PRIORITY_QUEUE_NAME)
public void consumePriorityQueue(String message, Channel channel,
@Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag,
@Header("priority") Integer priority) throws Exception {
try {
log.info("接收优先级订单消息:content={}, 优先级={}", message, priority);
// 模拟业务:处理订单(高优先级订单优先执行)
// orderService.processOrder(orderId);
channel.basicAck(deliveryTag, false);
} catch (Exception e) {
log.error("消费优先级订单消息失败", e);
channel.basicNack(deliveryTag, false, true);
}
}
}
4. 测试接口
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequiredArgsConstructor
public class PriorityTestController {
private final PriorityProducer priorityProducer;
@GetMapping("/priority/sendOrder")
public String sendOrder(@RequestParam Long orderId,
@RequestParam String userType,
@RequestParam int priority) {
priorityProducer.sendPriorityOrderMessage(orderId, userType, priority);
return "优先级订单消息发送成功";
}
}
3.4 镜像队列:高可用部署
核心概念
- 镜像队列:将队列复制到 RabbitMQ 集群的多个节点,当主节点宕机时,从节点自动接管队列,确保服务不中断;
- 核心价值:避免队列单点故障,提升 RabbitMQ 集群的高可用性。
适用场景
- 生产环境部署:所有核心业务队列(如订单、支付)都需配置镜像队列;
- 高可用要求高的场景:不允许因节点宕机导致队列不可用。
实现方式(集群配置)
-
搭建 RabbitMQ 集群(略,参考 RabbitMQ 官方文档);
-
配置镜像队列策略:
-
命令行方式:
# 为所有队列配置镜像策略(复制到所有节点) rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all"}' # 为特定队列配置镜像策略(复制到2个节点) rabbitmqctl set_policy ha-two "^ha." '{"ha-mode":"exactly","ha-params":2,"ha-sync-mode":"automatic"}' -
管理界面方式:进入 RabbitMQ Management → Admin → Policies → Add /update a policy,配置策略参数:
- Name:策略名称(如 ha-all);
- Pattern:队列名称匹配规则(如 ^ 匹配所有队列);
- Apply to:Queues;
- Definition:ha-mode=all(复制到所有节点)、ha-sync-mode=automatic(自动同步队列数据)。
-
四、RabbitMQ 典型使用场景与解决方案
4.1 场景 1:异步通信(服务解耦)
业务痛点
- 订单系统创建订单后,需调用支付、库存、日志、通知等多个服务,同步调用导致响应慢、耦合度高;
- 某一个服务故障(如通知服务宕机),会导致整个订单流程失败。
解决方案
- 采用 RabbitMQ 异步通信,订单系统发送消息后直接返回,其他服务异步消费;
- 交换机选型:Direct 交换机(精准路由到不同服务队列)。
架构设计
订单系统(生产者)→ Direct交换机 → 库存队列(库存服务)
→ 支付队列(支付服务)
→ 通知队列(通知服务)
→ 日志队列(日志服务)
核心源码
参考 2.1 节 Direct 交换机的实战源码,只需扩展队列和消费者即可。
4.2 场景 2:削峰填谷(秒杀高并发)
业务痛点
- 秒杀活动峰值 QPS 达 10 万 +,直接调用数据库会导致数据库宕机;
- 大量请求同时到达,服务线程池耗尽,导致服务不可用。
解决方案
- 采用 RabbitMQ 作为缓冲,秒杀请求先写入队列,消费者按数据库处理能力平滑消费;
- 交换机选型:Direct 交换机;
- 队列配置:普通队列 + 限流(消费者 prefetch 配置为 10,控制每秒消费速度)。
架构设计
用户秒杀请求 → API网关 → 秒杀服务(生产者)→ Direct交换机 → 秒杀队列 → 秒杀消费者(按能力消费)→ 数据库
核心优化
- 生产者限流:API 网关层限制每秒请求数,避免队列堆积过多;
- 消费者限流:
spring.rabbitmq.listener.simple.prefetch=10(每个消费者每次拉取 10 条消息); - 队列持久化:避免服务宕机导致消息丢失。
4.3 场景 3:广播通知(系统公告)
业务痛点
- 系统发布全局公告,需通知所有在线服务(如缓存服务、搜索服务、统计服务);
- 新增服务后,需修改发布公告的代码,耦合度高。
解决方案
- 采用 Fanout 交换机,发布公告时广播到所有绑定队列,新增服务只需绑定队列即可;
- 交换机选型:Fanout 交换机。
架构设计
公告服务(生产者)→ Fanout交换机 → 缓存服务队列
→ 搜索服务队列
→ 统计服务队列
→ 其他服务队列
核心源码
参考 2.3 节 Fanout 交换机的实战源码。
4.4 场景 4:定时任务(订单超时关闭)
业务痛点
- 订单创建后 30 分钟未支付需自动关闭,传统定时任务(如 Quartz)存在精度低、资源占用高的问题;
- 大量订单同时超时,导致数据库压力突增。
解决方案
- 采用 RabbitMQ 延迟队列,订单创建时发送延迟 30 分钟的消息,到期后消费消息关闭订单;
- 实现方式:延迟交换机插件(支持动态延迟时间)。
架构设计
订单系统(生产者)→ 延迟交换机 → 延迟队列 → 消费者(到期关闭订单)→ 数据库
核心源码
参考 3.2 节延迟队列的实战源码。
五、RabbitMQ 可靠性与性能优化
5.1 可靠性保障
- 消息持久化:交换机、队列、消息均设置为持久化(durable=true),避免 RabbitMQ 重启后消息丢失;
- 生产者确认:开启
publisher-confirm-type: correlated,确保消息成功发送到交换机; - 消费者 ACK:开启手动 ACK(
acknowledge-mode: manual),避免消费失败导致消息丢失; - 死信队列:处理无法消费的消息,便于排查问题;
- 幂等性处理:通过消息 ID 去重(如数据库唯一键、Redis 缓存),避免重复消费。
5.2 性能优化
- 连接池优化:使用 Spring AMQP 自带的连接池,配置合理的最大连接数和通道数;
- 消费者限流:通过
prefetch参数控制消费者每次拉取的消息数,避免消费者过载; - 序列化优化:使用 Protobuf 替代 JSON,减少消息体积,提升序列化效率;
- 队列拆分:将不同业务的队列拆分到不同交换机,避免队列堆积影响其他业务;
- 集群部署:采用 RabbitMQ 集群 + 镜像队列,提升并发处理能力和高可用性。
六、总结与最佳实践
RabbitMQ 的核心优势在于灵活的路由机制(四种交换机)和丰富的队列类型(死信、延迟、优先级队列),能够适配多种分布式场景。使用时需遵循以下最佳实践:
- 交换机选型:精准路由用 Direct,模糊路由用 Topic,广播用 Fanout,多属性匹配用 Headers;
- 队列选型:失败消息用死信队列,定时任务用延迟队列,重要消息用优先级队列;
- 可靠性优先:生产环境必须开启持久化、生产者确认、消费者 ACK、死信队列;
- 性能优化:合理配置连接池、prefetch 参数,避免队列堆积,采用集群部署提升并发;
- 监控运维:使用 RabbitMQ Management 监控队列堆积、消息吞吐量,结合 Prometheus + Grafana 实现告警。
本文提供的源码可直接复用,只需根据实际业务调整交换机、队列名称和业务逻辑即可快速落地。RabbitMQ 作为成熟的消息中间件,在分布式系统中应用广泛,掌握其核心特性和实战技巧,能有效解决异步通信、解耦、削峰填谷等核心问题。