死信队列
DLX,Dead-Letter-Exchange
利用DLX,当消息在一个队列中变成死信(dead message)之后,它被重新pulish到另一个Exchange,这个Exchange就是DLX
产生死信的集中情况
- 消息被拒绝(basic.reject/basic.nack)并且requeue=false(不执行重回队列)
- 消息TTL过期
- 队列达到最大长度
DLX也是一个正常的Exchange,和一般的Exchange没有区别,它能在任何队列上被指定,实际上就是设置某个队列的属性
当这个队列中有死信时,RabbitMQ就会自动的将这个消息重新发布到设置的Exchange上去,进而被路由到另一个队列。
可以监听这个队列中的消息做相应的处理,这个特性可以弥补RabbitMQ3.0以前支持的immediate参数的功能
死信队列的设置
首先需要设置死信队列的Exchange和Queue,然后进行绑定 - Exchange:dlx.Exchange
- Queue:dlx.Queue
- Routingkey:#
然后进行正常的声明Exchange、Channle、Binding,只不过需要在队列上加一个参数即可arguments.put(“x-dead-letter-exchange”,“dlx.exchange”);
这样消息在过期、requeue、队列在达到最大长度的时候,消息就可以直接路由到死信队列中
生产端
//下边是正常声明的普通的交换机、路由键
public static final String EXCHANGE_NAME = "test_exchange_dlx";
public static final String ROUTING_KEY = "dlx.key";
public static void main(String[] args) throws IOException, TimeoutException {
// 获取连接
Connection connection = ConnectionsUtils.getConnection();
// 创建信道
Channel channel = connection.createChannel();
// 发送消息
String message = "test message for exchange_dlx";
AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
.deliveryMode(2)
.expiration("10000")// 指定过期10秒
.build();
channel.basicPublish(EXCHANGE_NAME, ROUTING_KEY, properties, message.getBytes());
System.out.println("发送成功");
channel.close();
connection.close();
}
消费端
//下边是正常声明的普通的交换机、队列、路由键
public static final String EXCHANGE_NAME = "test_exchange_dlx";
public static final String EXCHANGE_TYPE = "topic";
public static final String ROUTING_KEY = "dlx.#";
public static final String QUEUE_NAME = "test_queue_dlx";
//下边声明的是死信交换机
public static final String EXCHANGE_DLX = "dlx.exchange";
public static final String QUEUE_DLX = "dlx.queue";
public static final String ROUTING_DLX = "#";
public static void main(String[] args) throws IOException, TimeoutException {
// 获取连接
Connection connection = ConnectionsUtils.getConnection();
// 创建信道
Channel channel = connection.createChannel();
// 声明交换机
channel.exchangeDeclare(EXCHANGE_NAME, EXCHANGE_TYPE, true, false, false ,null);
// 设置死信队列参数
Map<String, Object> arguments = new HashMap<String, Object>();
arguments.put("x-dead-letter-exchange",EXCHANGE_DLX);
// 声明队列
channel.queueDeclare(QUEUE_NAME, true, false, false, arguments);
// 绑定
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, ROUTING_KEY);
/**********死信队列的声明*********/
channel.exchangeDeclare(EXCHANGE_DLX, EXCHANGE_TYPE, true, false, null);
channel.queueDeclare(QUEUE_DLX, true, false, false, null);
channel.queueBind(QUEUE_DLX, EXCHANGE_DLX, ROUTING_DLX);
// 创建消费者进行监听获取消息
DefaultConsumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("接收消息message: " + new String(body));
}
};
channel.basicConsume(QUEUE_NAME, true, consumer);
}
启动消费端,这时在rabbitmq服务器已经有了exchange和queue的生成,关闭消费端,让消息无法进行消费,等待生产端发送消息10秒后,消息会从原test_queue_dlx队列转移到dlx.queue
我们看下效果截图