- 死信队列,英文缩写:DLX 。Dead Letter Exchange(死信交换机),当消息成为Dead message后,可以被重新发送到另一个交换机,这个交换机就是DLX。
消息成为死信的三种情况:
-
队列消息长度到达限制;
-
消费者拒接消费消息,basicNack/basicReject,并且不把消息重新放入原目标队列,requeue=false;
-
原队列存在消息过期设置,消息到达超时时间未被消费
代码实现(spring整合rabbitmq为例)
声明正常队列,并设置成为私信队列的前提,(即设置TTL、队列的最大长度、消费者端拒绝接受消息)
设置TTL和队列最大长度,并且指定死信队列的交换机、指定信息传递到死信队列后的路由键;在配置文件代码如下:(这里有一个很奇怪的地方,我的ttl设置不是10000代码运行起来就报IOException,至今找不出问题所在)
测试代码:
for (int i = 0; i <20 ; i++) {
//发送消息
rabbitTemplate.convertAndSend("test_exchange_dlx", "test.dlx.xx", "dlxdlxdlx消息-----------");
}
效果:发送20条信息到队列,但是设置了10条是最大长度,所以发送的10条会传递到死信队列;
剩余的10条因为设置了TTL,所以过了10秒之后那10条信息也传递到了死信队列,
并且路由键也编程了dlx.hha
测试拒绝签收从而传递到死信队列的要在消费者端拒绝签收才能看出效果,步骤如下:
定义监听器监听队列消息,并设置异常以便拒绝签收:
<!-- 扫描监听器package-->
<context:component-scan base-package="com.listener"/>
<rabbit:listener-container connection-factory="connectionFactory" acknowledge="manual" prefetch="1">
<rabbit:listener ref="dlxListener" queue-names="test_queue_dlx"></rabbit:listener>
</rabbit:listener-container>
@Component
public class DlxListener implements ChannelAwareMessageListener {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
long deliveryTag = message.getMessageProperties().getDeliveryTag();
try {
//System.out.println(new String(message.getBody()));
int i=3/0;//有异常,不自动签收,抓取异常后拒绝签收并且不重回队列
System.out.println("处理业务逻辑");
//手动签收
channel.basicAck(deliveryTag,true);
}catch (Exception e){
//第三个参数是重回队列:false
channel.basicNack(deliveryTag,true,false);
}
}
}
效果:监听器监听到队列消息,因为出现异常直接将消息传递到死信队列。
总结:
-
死信交换机和死信队列和普通的没有区别
-
当消息成为死信后,如果该队列绑定了死信交换机,则消息会被死信交换机重新路由到死信队列
-
消息成为死信的三种情况:
队列消息长度到达限制;
消费者拒接消费消息,并且不重回队列;
原队列存在消息过期设置,消息到达超时时间未被消费;