rabbitmq 死信队列

6,392 阅读2分钟

死信队列: DLX,dead-letter-exchange

利用 dlx,当消息在一个队列中变成死信 (dead message) 之后,它能被重新 publish 到另一个 exchange,这个 exchange 就是 dlx

消息变成死信的原因有:

1.消息被拒绝 (basic.reject / basic.nack) 并且 reQueue=false

2.消息 TTL 过期

3.队列达到最大长度了

dlx 也是一个正常的 exchange,和一般的 exchange 没什么区别,它能在任何队列上被指定,实际上就是设置一个属性。

当这个队列中有死信时,rabbitMQ 就会自动的将这个消息重新发布到设置的 exchange 上去,进而被路由到另一个队列。

可以监听这个队列中消息做相应的处理,这个特性可以弥补 rabbitMQ3.0 以前支持的 immediate 参数功能。

死信队列的设置:

首先要设置死信队列的 exchange 和 queue,然后进行绑定:

  exchange: dlx.exchange

  queue: dlx.queue

  routingkey:  #

然后进行正常声明交换机、队列、绑定,只不过需要在队列加上一个参数即可: argument.put("x-dead-letter-exchange", "dlx.exchange");

这样消息在过期、reQueue、队列在达到最大长度时,消息就可以直接路由到死信队列

代码地址:    https://github.com/hmilyos/rabbitmqdemo.git  rabbitmq-api 项目下
public class Producer {

	private static final Logger log = LoggerFactory.getLogger(Producer.class);
	
	public static void main(String[] args) throws IOException, TimeoutException {
		 ConnectionFactory connectionFactory = new ConnectionFactory();
	        connectionFactory.setHost(RabbitMQCommon.RABBITMQ_HOST);
	        connectionFactory.setPort(RabbitMQCommon.RABBITMQ_PORT);
	        connectionFactory.setVirtualHost(RabbitMQCommon.RABBITMQ_DEFAULT_VIRTUAL_HOST);

	        Connection connection = connectionFactory.newConnection();
	        Channel channel = connection.createChannel();

	        //注意,这只是普通的交换机和routingKey
	        String exchange = "test_dlx_exchange";
	        String routingKey = "dlx.save";

	        for (int i = 0; i < 1; i++) {
	            String msg = "Hello RabbitMQ DLX Message" + i;
	            AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
	                    .deliveryMode(2)
	                    .contentEncoding("UTF-8")
	                    .expiration("10000")
	                    .build();
	            log.info("生产端发送:{}", msg);
	            channel.basicPublish(exchange, routingKey, true, properties, msg.getBytes());
	        }
	}
}

/**
 *	 死信队列
 *
 */
public class Consumer {

	private static final Logger log = LoggerFactory.getLogger(Consumer.class);
	
	public static void main(String[] args) throws IOException, TimeoutException {
		//1 创建ConnectionFactory
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost(RabbitMQCommon.RABBITMQ_HOST);
        connectionFactory.setPort(RabbitMQCommon.RABBITMQ_PORT);
        connectionFactory.setVirtualHost(RabbitMQCommon.RABBITMQ_DEFAULT_VIRTUAL_HOST);
        //2 获取Connection
        Connection connection = connectionFactory.newConnection();
        //3 通过Connection创建一个新的Channel
        Channel channel = connection.createChannel();

        // 这就是一个普通的交换机 和 队列 以及路由
        String exchangeName = "test_dlx_exchange";
        String routingKey = "dlx.#";
        String queueName = "test_dlx_queue";
        channel.exchangeDeclare(exchangeName, "topic", true, false, null);

        Map<String, Object> agruments = new HashMap<String, Object>();
        agruments.put("x-dead-letter-exchange", "dlx.exchange");
        //这个agruments属性,要设置到声明队列上
        channel.queueDeclare(queueName, true, false, false, agruments);
        channel.queueBind(queueName, exchangeName, routingKey);

        //要进行死信队列的声明: dlx.exchange/queue都是由你自己命名的,只不过为了这里只是为了简洁明了而已
        channel.exchangeDeclare("dlx.exchange", "topic", true, false, null);
        channel.queueDeclare("dlx.queue", true, false, false, null);
        channel.queueBind("dlx.queue", "dlx.exchange", "#");

        channel.basicConsume(queueName, true, new MyConsumer(channel));
        log.info("消费端启动成功");
        
	}
}
public class MyConsumer extends DefaultConsumer {

	private static final Logger log = LoggerFactory.getLogger(MyConsumer.class);

	public MyConsumer(Channel channel) {
		super(channel);
	}

	@Override
	public void handleDelivery(String consumerTag, // 消费者标签
			Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
		log.info("----dlx--MyConsumer-----consume message----------");
		log.info("consumerTag: " + consumerTag);
		log.info("envelope: " + envelope);
		log.info("properties: " + properties);
		log.info("body: " + new String(body));
	}

}

先把消费端启动,去管控台查看 test_dlx_exchange 以及 test_dlx_queue 这两个普通的交换机、队列, 死信队列 dlx.queue 以及绑定的 dlx.exchange 是否创建成功

确认创建成功就关闭消费端,然后再启动生产端,这时候消息没被消费,一直在 test_dlx_queue 中,
直到设置的超时时间后,消息就被转发到死信队列中
自此,死信队列的简单用法介绍完毕。