导言
RabbitMQ版本: 4.0.5
JDK: 17
Spring Cloud Alibaba 2023.0.1.0
一. 安装
拉取镜像
docker pull rabbitmq:management
启动容器
docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:management
进入容器,启动插件
进入容器
docker exec -it 容器id /bin/bash
启动所有插件
rabbitmq-plugins enable rabbitmq_management
安装完成
到这里就已经安装完成了,通过 http://localhost:15672
访问rabbitmq
的dashboard
, 因为没有设置密码, 因此用默认用户密码登录
用户名: guest
密码: guest
延时队列
rabbitmq
本身不支持延时队列功能, 但是可以通过两种途径实现延时队列功能
第一: 使用延时队列插件
第二: 使用TTL + 死信队列
第二种方式的实现原理:
在MQ中可以给消息设置过期时间 TTL, 当消息过期就会进入死信队列, 在死信队列中消费消息从而实现延时队列功能, 但是要保证消息不能在原始队列中就被消费
第一种方式:
首先需要下载延时队列插件
https://www.rabbitmq.com/community-plugins(这是rabbitmq插件的下载路径)
https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases(这是延时队列插件下载路径)
将下载好的插件复制到rabbitmq
的插件文件夹下, 这里我已经将插件放在了临时文件夹tmp
下, 格式为: docker cp 插件路径 容器文件夹路径(格式为 容器id:文件相对路径)
docker cp /tmp/rabbitmq_delayed_message_exchange-4.0.2.ez 09ddf39c3b55:/plugins
复制之后进入容器
docker exec -it rabbitmq /bin/bash
启动插件, 因为之前就已经启动其他插件, 所以这里只需要启动延时队列插件
rabbitmq-plugins enable rabbitmq_delayed_message_exchange
如图只要在创建交换机的地方有如下选项就说明安装成功
延时队列使用demo:
延时交换机配置:
public final static String ERP_DELAYED_CANCEL_ORDER_QUEUE = "erp-delayed-cancel-queue";
public final static String ERP_DELAYED_CANCEL_ORDER_EXCHANGE = "erp-delayed-cancel-exchange";
public final static String ERP_DELAYED_CANCEL_ORDER_ROUTING = "erp-delayed-cancel-routing";
public final static String ERP_DELAYED_CANCEL_ORDER_DLQ_QUEUE = "erp-delayed-cancel-dlq-queue";
public final static String ERP_DELAYED_CANCEL_ORDER_DLQ_EXCHANGE = "erp-delayed-cancel-dlq-exchange";
public final static String ERP_DELAYED_CANCEL_ORDER_DLQ_ROUTING = "erp-delayed-cancel-dlq-routing";
/**
* 取消订单的延时交换机
* @return
*/
@Bean
public CustomExchange delayedCancelOrderExchange() {
return new CustomExchange(ERP_DELAYED_CANCEL_ORDER_EXCHANGE, "x-delayed-message", true, false,
Map.of("x-delayed-type", "direct"));
}
/**
* 延时取消订单队列
* @return
*/
@Bean
public Queue delayedCancelOrderQueue() {
Map<String, Object> args = new HashMap<>();
args.put("x-dead-letter-exchange", ERP_DELAYED_CANCEL_ORDER_DLQ_EXCHANGE);
args.put("x-dead-letter-routing-key", ERP_DELAYED_CANCEL_ORDER_DLQ_ROUTING);
return new Queue(ERP_DELAYED_CANCEL_ORDER_QUEUE, true, false, false, args);
}
/**
* 延时取消订单队列和交换机绑定关系
* @return
*/
@Bean
public Binding delayedCancelOrderBinding() {
return BindingBuilder.bind(delayedCancelOrderQueue())
.to(delayedCancelOrderExchange())
.with(ERP_DELAYED_CANCEL_ORDER_ROUTING)
.noargs();
}
/**
* 延时取消订单死信队列
* @return
*/
@Bean
public Queue delayedCancelOrderDeadLetterQueue() {
return new Queue(ERP_DELAYED_CANCEL_ORDER_DLQ_QUEUE);
}
/**
* 延时取消订单死信交换机
* @return
*/
@Bean
public DirectExchange delayedCancelOrderDeadLetterExchange() {
return new DirectExchange(ERP_DELAYED_CANCEL_ORDER_DLQ_EXCHANGE, true, false);
}
/**
* 延时取消订单死信交换机与队列绑定关系
* @return
*/
@Bean
public Binding delayedCancelOrderDeadLetterBinding() {
return BindingBuilder.bind(delayedCancelOrderDeadLetterQueue())
.to(delayedCancelOrderDeadLetterExchange())
.with(ERP_DELAYED_CANCEL_ORDER_DLQ_ROUTING);
}
发送延时消息demo:
/**
* 发送延时消息(需配置延时交换机)
* @param exchange 交换机
* @param routing 路由
* @param message 消息
* @param delayTime 延时时间 (分钟)
*/
public void sendDelayMessage(String exchange, String routing, String message, long delayTime) {
log.info("延时取消订单消息发送完毕,{}" , message);
Message msg = MessageBuilder.withBody(message.getBytes(StandardCharsets.UTF_8)).setHeader("x-delay", delayTime * 60 * 1000).build();
rabbitTemplate.convertAndSend(exchange, routing, msg);
}
二. 简介
交换机介绍
- Direct Exchange(直连交换机):
直连交换机会根据消息携带的路由键(Routing Key)精确匹配绑定键(Binding Key),然后将消息路由到匹配的队列中。
使用场景:通常用于消息的精确投递,适合点对点通信。
举例:如果消息的路由键是 “error”,那么消息会被发送到绑定键也为 “error” 的队列。 - Fanout Exchange(扇形交换机):
扇形交换机会将接收到的消息广播给所有绑定到该交换机的队列,忽略路由键。
使用场景:适合广播场景,比如发送一条通知给多个消费者。
举例:发布订阅模式,消息会被投递到所有绑定到该交换机的队列中,不管路由键是什么。 - Topic Exchange(主题交换机):
主题交换机允许使用通配符进行路由,消息会根据路由键匹配绑定键的模式(支持通配符*
和#
)。
使用场景:适合需要按某些规则或模式发送消息的场景。
通配符:
*
匹配一个单词。
#
匹配零个或多个单词。
举例:路由键是log.error.system
,可以匹配绑定键为log.*.system
或log.#
的队列。 - Headers Exchange(头部交换机):
头部交换机不依赖路由键,而是根据消息头(Headers)中设置的键值对进行匹配。
使用场景:当消息路由逻辑更加复杂或需要基于消息属性(头部信息)进行路由时,可以使用这种交换机。
举例:消息头里包含x-match=all
时,消息必须匹配所有头部值,x-match=any
时只需要匹配任意一个头部值。