一、RabbitMQ是什么?
1. 一句话解释
RabbitMQ是开源的消息中间件 ,就像邮局系统:
-
生产者是寄信人
-
消费者是收信人
-
RabbitMQ是邮局
-
交换器是分拣中心
-
队列是邮箱
2. 为什么需要RabbitMQ?
// 没有消息队列的系统
class 传统订单系统 {
public void 创建订单() {
1. 保存订单到数据库
2. 发短信通知用户
3. 扣减库存
4. 记录日志
5. 更新推荐系统
// 问题:一个失败,整个回滚!
// 问题:系统紧耦合!
}
}
// 有RabbitMQ的系统
class 现代订单系统 {
public void 创建订单() {
1. 保存订单
2. 发消息到RabbitMQ:"订单已创建"
3. 立即返回成功
// RabbitMQ负责通知:
// 短信服务:收到消息 → 发短信
// 库存服务:收到消息 → 扣库存
// 日志服务:收到消息 → 记日志
// 各自处理,互不影响
}
}
二、核心概念(必须理解!)
1. 六大核心组件
生产者(Producer)→ 交换器(Exchange)→ 队列(Queue)→ 消费者(Consumer)
│ │ │
消息(Message) 绑定(Binding) 通道(Channel)
2. 详细解释每个组件
java
// 1. 消息(Message)
消息 = {
headers: {}, // 头部信息
properties: {}, // 属性(优先级、持久化等)
body: "内容" // 消息体
}
// 2. 生产者(Producer)
class 生产者 {
public void 发送消息() {
// 创建消息
消息 msg = new 消息("订单1001创建");
// 发送到交换器
channel.basicPublish(
"订单交换器", // 交换器
"订单.创建", // 路由键
null, // 属性
msg.getBytes() // 消息体
);
}
}
// 3. 交换器(Exchange)- 最重要!
交换器是"邮局的分拣中心"
接收生产者消息,根据规则路由到队列
// 4. 队列(Queue)
队列是"邮箱"
存储消息,等待消费者取走
// 5. 消费者(Consumer)
class 消费者 {
public void 消费消息() {
// 从队列取消息
消息 msg = channel.basicGet("订单队列");
// 处理消息
处理订单(msg);
// 确认消费完成
channel.basicAck(msg);
}
}
// 6. 绑定(Binding)
绑定是"分拣规则"
告诉交换器:什么样的消息放到哪个队列
三、四种交换器类型(核心!)
1. Direct Exchange(直连交换器)- 精确匹配
比喻:快递员送快递,必须门牌号完全匹配
生产者 → Direct Exchange → 队列
↓
根据 Routing Key 精确匹配
例子:
消息1: Routing Key = "订单.创建" → 队列1
消息2: Routing Key = "订单.支付" → 队列2
消息3: Routing Key = "订单.创建" → 队列1
代码示例:
java
// 1. 声明Direct交换器
channel.exchangeDeclare(
"订单交换器", // 交换器名
"direct", // 类型
true // 持久化
);
// 2. 绑定队列
channel.queueBind(
"订单创建队列", // 队列
"订单交换器", // 交换器
"订单.创建" // Routing Key
);
channel.queueBind(
"订单支付队列",
"订单交换器",
"订单.支付"
);
// 3. 发送消息
channel.basicPublish(
"订单交换器",
"订单.创建", // 精确匹配
null,
"订单1001创建".getBytes()
);
// 结果:消息进入"订单创建队列"
2. Topic Exchange(主题交换器)- 模式匹配
比喻:用通配符订阅感兴趣的话题
* 匹配一个单词
# 匹配零个或多个单词
生产者 → Topic Exchange → 队列
↓
根据模式匹配
例子:
队列1绑定键: "订单.*.创建"
- 匹配: "订单.电商.创建" ✓
- 匹配: "订单.外卖.创建" ✓
- 不匹配: "订单.创建" ❌(少一个单词)
队列2绑定键: "订单.#"
- 匹配: "订单.创建" ✓
- 匹配: "订单.电商.创建" ✓
- 匹配: "订单.电商.外卖.创建" ✓
代码示例:
java
// 1. 声明Topic交换器
channel.exchangeDeclare("日志交换器", "topic", true);
// 2. 绑定队列
// 错误日志队列
channel.queueBind("错误队列", "日志交换器", "*.error");
// 支付日志队列
channel.queueBind("支付队列", "日志交换器", "payment.*");
// 用户行为队列
channel.queueBind("用户队列", "日志交换器", "user.#");
// 3. 发送消息
// 消息1:进入错误队列
channel.basicPublish("日志交换器", "payment.error", null,
"支付出错".getBytes());
// 消息2:进入支付队列
channel.basicPublish("日志交换器", "payment.success", null,
"支付成功".getBytes());
// 消息3:进入用户队列
channel.basicPublish("日志交换器", "user.login", null,
"用户登录".getBytes());
3. Fanout Exchange(扇出交换器)- 广播
java
比喻:小区广播,所有人都能听到
生产者 → Fanout Exchange → 所有绑定队列
↓
消息复制多份
例子:
消息 → Fanout Exchange → 队列1
→ 队列2
→ 队列3
所有队列都收到同样的消息
代码示例:
java
// 1. 声明Fanout交换器
channel.exchangeDeclare("新闻交换器", "fanout", true);
// 2. 绑定队列(不需要Routing Key)
channel.queueBind("短信队列", "新闻交换器", ""); // 空字符串
channel.queueBind("邮件队列", "新闻交换器", "");
channel.queueBind("App队列", "新闻交换器", "");
// 3. 发送消息
channel.basicPublish("新闻交换器", "", null, // Routing Key为空
"系统升级通知".getBytes());
// 结果:三个队列都收到消息
4. Headers Exchange(头交换器)- 匹配Header
根据消息的Header属性匹配
x-match: all(所有header必须匹配)
x-match: any(任意header匹配)
生产者 → Headers Exchange → 队列
↓
根据Header匹配
代码示例:
java
// 1. 声明Headers交换器
channel.exchangeDeclare("header交换器", "headers", true);
// 2. 绑定队列(设置匹配规则)
Map<String, Object> 匹配条件 = new HashMap<>();
匹配条件.put("format", "pdf");
匹配条件.put("type", "report");
匹配条件.put("x-match", "all"); // 必须同时满足
channel.queueBind("报告队列", "header交换器", "", 匹配条件);
// 3. 发送消息(设置Header)
AMQP.BasicProperties props = new AMQP.BasicProperties.Builder()
.headers(匹配条件)
.build();
channel.basicPublish("header交换器", "", props,
"月度报告.pdf".getBytes());
四、Spring Boot整合实战
1. 添加依赖
<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
# 连接池配置
connection-timeout: 3000
template:
retry:
enabled: true
max-attempts: 3
# 确认机制
publisher-confirm-type: correlated
publisher-returns: true
listener:
simple:
acknowledge-mode: manual # 手动确认
prefetch: 10 # 每次取多少条
3. 配置类
@Configuration
public class RabbitMQConfig {
// 1. 声明交换器
@Bean
public TopicExchange orderExchange() {
return new TopicExchange("order.exchange", true, false);
}
@Bean
public FanoutExchange logExchange() {
return new FanoutExchange("log.exchange", true, false);
}
// 2. 声明队列
@Bean
public Queue orderCreateQueue() {
return new Queue("order.create.queue", true);
}
@Bean
public Queue orderPayQueue() {
return new Queue("order.pay.queue", true);
}
@Bean
public Queue smsQueue() {
return new Queue("sms.queue", true);
}
// 3. 声明死信队列
@Bean
public Queue orderDeadLetterQueue() {
Map<String, Object> args = new HashMap<>();
args.put("x-dead-letter-exchange", "order.exchange");
args.put("x-dead-letter-routing-key", "order.dead");
args.put("x-message-ttl", 10000); // 10秒过期
return new Queue("order.dlx.queue", true, false, false, args);
}
// 4. 绑定队列到交换器
@Bean
public Binding orderCreateBinding() {
return BindingBuilder.bind(orderCreateQueue())
.to(orderExchange())
.with("order.create");
}
@Bean
public Binding orderPayBinding() {
return BindingBuilder.bind(orderPayQueue())
.to(orderExchange())
.with("order.pay");
}
@Bean
public Binding smsBinding() {
return BindingBuilder.bind(smsQueue())
.to(logExchange());
}
}
4. 生产者
java
@Component
@Slf4j
public class OrderProducer {
@Autowired
private RabbitTemplate rabbitTemplate;
// 发送订单创建消息
public void sendOrderCreate(Order order) {
// 设置消息属性
MessageProperties props = MessagePropertiesBuilder.newInstance()
.setContentType(MessageProperties.CONTENT_TYPE_JSON)
.setHeader("orderId", order.getId())
.setExpiration("10000") // 10秒过期
.build();
Message message = MessageBuilder
.withPayload(order)
.andProperties(props)
.build();
// 发送消息
CorrelationData correlationData = new CorrelationData(order.getId());
rabbitTemplate.convertAndSend(
"order.exchange",
"order.create",
message,
correlationData
);
log.info("发送订单创建消息: {}", order.getId());
}
// 发送延迟消息
public void sendDelayMessage(Order order, int delaySeconds) {
MessageProperties props = MessagePropertiesBuilder.newInstance()
.setExpiration(String.valueOf(delaySeconds * 1000))
.build();
Message message = MessageBuilder
.withPayload(order)
.andProperties(props)
.build();
// 发送到死信交换器
rabbitTemplate.convertAndSend(
"order.exchange.dlx",
"order.delay",
message
);
}
}
5. 消费者
java
@Component
@Slf4j
public class OrderConsumer {
// 1. 订单创建消费者
@RabbitListener(queues = "order.create.queue")
@RabbitHandler
public void handleOrderCreate(Order order,
Channel channel,
@Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) {
try {
log.info("收到订单创建消息: {}", order);
// 业务处理
processOrder(order);
// 手动确认
channel.basicAck(deliveryTag, false);
} catch (Exception e) {
log.error("处理订单失败", e);
// 处理失败
// 重试3次
if (getRetryCount(order) < 3) {
// 拒绝消息,重新入队
channel.basicNack(deliveryTag, false, true);
} else {
// 超过重试次数,进入死信队列
channel.basicNack(deliveryTag, false, false);
}
}
}
// 2. 订单支付消费者
@RabbitListener(queues = "order.pay.queue")
public void handleOrderPay(Order order) {
log.info("处理订单支付: {}", order);
paymentService.process(order);
}
// 3. 死信队列消费者
@RabbitListener(queues = "order.dlx.queue")
public void handleDeadLetter(Order order) {
log.warn("收到死信消息: {}", order);
// 处理死信:发邮件通知、记录日志等
alertService.sendAlert("订单处理失败: " + order.getId());
}
}
五、高级特性
1. 消息确认机制
// 生产者确认
@Component
public class ProducerConfirmCallback implements RabbitTemplate.ConfirmCallback {
@Override
public void confirm(CorrelationData correlationData,
boolean ack,
String cause) {
if (ack) {
log.info("消息发送成功: {}", correlationData.getId());
} else {
log.error("消息发送失败: {}, 原因: {}",
correlationData.getId(), cause);
// 重试逻辑
}
}
}
// 配置确认回调
@Configuration
public class RabbitConfig {
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate template = new RabbitTemplate(connectionFactory);
template.setConfirmCallback(new ProducerConfirmCallback());
return template;
}
}
2. 消息可靠性保证
// 完整可靠性方案
@Component
public class ReliableMessageService {
// 1. 数据库存储消息(保证不丢)
@Transactional
public void sendReliableMessage(Message message) {
// 1.1 保存到数据库
messageDao.save(message);
try {
// 1.2 发送到RabbitMQ
rabbitTemplate.convertAndSend(
message.getExchange(),
message.getRoutingKey(),
message.getBody()
);
// 1.3 更新状态为已发送
message.setStatus("SENT");
messageDao.update(message);
} catch (Exception e) {
// 发送失败,记录日志
log.error("消息发送失败", e);
}
}
// 2. 定时任务重发失败消息
@Scheduled(fixedDelay = 60000) // 每分钟执行
public void retryFailedMessages() {
List<Message> failedMessages = messageDao.findByStatus("FAILED");
for (Message message : failedMessages) {
if (message.getRetryCount() < 3) {
sendReliableMessage(message);
message.setRetryCount(message.getRetryCount() + 1);
} else {
message.setStatus("DEAD");
// 进入死信处理
}
messageDao.update(message);
}
}
}
3. 延迟队列实现
// 方案1:使用TTL+死信队列
@Configuration
public class DelayQueueConfig {
// 延迟交换器
@Bean
public DirectExchange delayExchange() {
return new DirectExchange("delay.exchange");
}
// 延迟队列(设置TTL)
@Bean
public Queue delayQueue() {
Map<String, Object> args = new HashMap<>();
args.put("x-dead-letter-exchange", "order.exchange");
args.put("x-dead-letter-routing-key", "order.cancel");
args.put("x-message-ttl", 300000); // 5分钟
return new Queue("delay.queue", true, false, false, args);
}
@Bean
public Binding delayBinding() {
return BindingBuilder.bind(delayQueue())
.to(delayExchange())
.with("delay.order");
}
}
// 方案2:使用RabbitMQ延迟插件
@Bean
public CustomExchange delayPluginExchange() {
Map<String, Object> args = new HashMap<>();
args.put("x-delayed-type", "direct");
return new CustomExchange(
"delayed.exchange",
"x-delayed-message", // 使用插件
true,
false,
args
);
}
六、实际应用场景
场景1:电商订单系统
@Component
public class OrderSystem {
// 订单创建
public void createOrder(OrderDTO dto) {
// 1. 保存订单
Order order = orderService.create(dto);
// 2. 发送订单创建消息
rabbitTemplate.convertAndSend(
"order.exchange",
"order.create",
order
);
// 3. 发送延迟消息(30分钟未支付取消)
MessageProperties props = new MessageProperties();
props.setExpiration("1800000"); // 30分钟
Message message = new Message(
order.getId().toString().getBytes(),
props
);
rabbitTemplate.send(
"delay.exchange",
"order.delay",
message
);
}
// 消费者:库存服务
@RabbitListener(queues = "inventory.queue")
public void handleInventory(Order order) {
inventoryService.deductStock(order);
}
// 消费者:短信服务
@RabbitListener(queues = "sms.queue")
public void handleSMS(Order order) {
smsService.sendOrderSuccess(order.getUserId());
}
// 消费者:取消未支付订单
@RabbitListener(queues = "order.cancel.queue")
public void handleCancelOrder(String orderId) {
orderService.cancelIfNotPaid(orderId);
}
}
场景2:日志收集系统
@Component
public class LogSystem {
// 发送日志
public void sendLog(Log log) {
String routingKey = log.getLevel() + "." + log.getModule();
rabbitTemplate.convertAndSend(
"log.topic.exchange",
routingKey,
log
);
}
// 消费者:错误日志(发告警)
@RabbitListener(queues = "error.log.queue")
public void handleErrorLog(Log log) {
if ("ERROR".equals(log.getLevel())) {
alertService.sendAlert(log);
}
}
// 消费者:支付日志(统计)
@RabbitListener(queues = "payment.log.queue")
public void handlePaymentLog(Log log) {
if (log.getModule().contains("payment")) {
statsService.collectPaymentStats(log);
}
}
// 消费者:所有日志(存储到ES)
@RabbitListener(queues = "all.log.queue")
public void handleAllLog(Log log) {
esService.indexLog(log);
}
}
场景3:微服务事件驱动
// 用户服务
@Component
public class UserService {
public void register(User user) {
// 1. 保存用户
userDao.save(user);
// 2. 发布用户注册事件
UserRegisteredEvent event = new UserRegisteredEvent(user);
rabbitTemplate.convertAndSend(
"user.event.exchange",
"user.registered",
event
);
}
}
// 积分服务(监听用户注册)
@Component
public class PointsService {
@RabbitListener(queues = "user.registered.queue")
public void handleUserRegistered(UserRegisteredEvent event) {
// 新用户注册,送积分
pointsService.addWelcomePoints(event.getUserId());
}
}
// 推荐服务
@Component
public class RecommendService {
@RabbitListener(queues = "user.registered.queue")
public void handleUserRegistered(UserRegisteredEvent event) {
// 新用户注册,初始化推荐列表
recommendService.initRecommendations(event.getUserId());
}
}
七、集群和高可用
1. 集群模式
# 1. 启动3个RabbitMQ节点
# 节点1
RABBITMQ_NODENAME=rabbit1
RABBITMQ_NODE_PORT=5672
# 节点2
RABBITMQ_NODENAME=rabbit2
RABBITMQ_NODE_PORT=5673
# 节点3
RABBITMQ_NODENAME=rabbit3
RABBITMQ_NODE_PORT=5674
# 2. 加入集群
# 在节点2执行
rabbitmqctl stop_app
rabbitmqctl join_cluster rabbit1@hostname
rabbitmqctl start_app
# 3. 设置镜像队列
rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all"}'
2. Spring Boot集群配置
spring:
rabbitmq:
addresses: host1:5672,host2:5673,host3:5674
username: guest
password: guest
virtual-host: /
# 集群配置
connection-timeout: 3000
publisher-confirm-type: correlated
publisher-returns: true
cache:
channel:
size: 25
connection:
mode: connection
size: 1
八、监控和管理
1. 管理界面
访问:http://localhost:15672
默认账号:guest/guest
功能:
1. 查看队列深度
2. 查看消息速率
3. 管理用户权限
4. 导入导出配置
5. 查看连接信息
2. 关键监控指标
# 命令行监控
# 查看队列
rabbitmqctl list_queues name messages_ready messages_unacknowledged
# 查看交换器
rabbitmqctl list_exchanges name type
# 查看绑定
rabbitmqctl list_bindings
# 查看连接
rabbitmqctl list_connections
# 查看消费者
rabbitmqctl list_consumers
3. Prometheus监控
# 启用Prometheus插件
rabbitmq-plugins enable rabbitmq_prometheus
# 访问指标
http://localhost:15692/metrics
# 关键指标:
rabbitmq_queue_messages_ready
rabbitmq_queue_messages_unacknowledged
rabbitmq_queue_messages
rabbitmq_connections
rabbitmq_channels
九、常见问题解决
问题1:消息堆积怎么办?
// 解决方案
@Component
public class MessageBacklogHandler {
// 1. 增加消费者
@Bean
public SimpleRabbitListenerContainerFactory containerFactory() {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConcurrentConsumers(10); // 并发消费者
factory.setMaxConcurrentConsumers(20); // 最大并发
return factory;
}
// 2. 监控队列深度
@Scheduled(fixedRate = 60000)
public void monitorQueueDepth() {
Queue queue = rabbitAdmin.getQueueInfo("order.queue");
if (queue != null && queue.getMessageCount() > 10000) {
// 告警
alertService.sendAlert("队列堆积: " + queue.getMessageCount());
// 动态扩容
scaleConsumers();
}
}
// 3. 死信队列处理
@RabbitListener(queues = "dead.letter.queue")
public void handleDeadLetter(Message message) {
// 记录、告警、人工处理
logService.logDeadLetter(message);
}
}
问题2:消息重复消费
// 解决方案:幂等性处理
@Component
public class IdempotentConsumer {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@RabbitListener(queues = "order.queue")
public void handleOrder(Order order, Channel channel,
@Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) {
String messageId = order.getMessageId();
// 1. 检查是否已处理
String key = "processed:" + messageId;
if (redisTemplate.hasKey(key)) {
// 已处理,直接确认
channel.basicAck(deliveryTag, false);
return;
}
try {
// 2. 处理业务
processOrder(order);
// 3. 标记为已处理
redisTemplate.opsForValue().set(key, "1", 24, TimeUnit.HOURS);
// 4. 确认消息
channel.basicAck(deliveryTag, false);
} catch (Exception e) {
// 处理失败
channel.basicNack(deliveryTag, false, true);
}
}
}
十、性能优化
1. 生产环境配置
spring:
rabbitmq:
# 连接池
cache:
channel:
size: 25
checkout-timeout: 1000
connection:
mode: connection
size: 1
# 确认机制
publisher-confirm-type: correlated
publisher-returns: true
# 消费者
listener:
simple:
acknowledge-mode: manual
prefetch: 100
concurrency: 10
max-concurrency: 20
retry:
enabled: true
max-attempts: 3
initial-interval: 1000
2. 最佳实践
// 1. 消息大小控制
public void sendMessage(Order order) {
// 消息不要太大,建议<1MB
if (order.getSize() > 1024 * 1024) {
compressOrder(order);
}
// 发送...
}
// 2. 批量发送
public void batchSend(List<Order> orders) {
for (int i = 0; i < orders.size(); i += 100) {
List<Order> batch = orders.subList(i, Math.min(i + 100, orders.size()));
rabbitTemplate.convertAndSend("exchange", "key", batch);
}
}
// 3. 合理设置TTL
public void sendWithTTL(Order order, int ttlSeconds) {
MessageProperties props = new MessageProperties();
props.setExpiration(String.valueOf(ttlSeconds * 1000));
// 发送...
}
十一、一句话总结
RabbitMQ = 邮局系统 + 灵活路由 + 企业级可靠
核心是交换器模型:
-
Direct:精确送快递
-
Topic:模式订阅
-
Fanout:小区广播
-
Headers:属性匹配
适用场景:需要灵活路由、复杂消息模式、与企业系统集成、快速开发的场景。