美文网首页
RabbitMQ学习(六)死信队列

RabbitMQ学习(六)死信队列

作者: kobe0429 | 来源:发表于2018-11-28 16:10 被阅读0次

DLX:Dead-Letter-Exchange

当消息在一个队列中变成死信(dead message)之后,它能被重新publish到另一个Exchange,这个Exchange就是DLX。
消息变成死信队列有以下3种情况:

消息被拒绝(basic.reject/ basic.nack)并且requeue=false
消息TTL过期(参考:RabbitMQ之TTL(Time-To-Live 过期时间))
队列达到最大长度
DLX也是一个正常的Exchange,和一般的Exchange没有区别,它能在任何的队列上被指定,实际上就是设置某个队列的属性,当这个队列中有死信时,RabbitMQ就会自动的将这个消息重新发布到设置的Exchange上去,进而被路由到另一个队列,可以监听这个队列中消息做相应的处理,这个特性可以弥补RabbitMQ 3.0以前支持的immediate参数(可以参考RabbitMQ之mandatory和immediate)的功能。
下面直接上代码,理解起来就非常简单了
生产者类:

package com.bfxy.rabbitmq.api.dlx;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

public class Producer {

    
    public static void main(String[] args) throws Exception {
        
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("10.136.197.244");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("/");
        connectionFactory.setUsername("admin");
        connectionFactory.setPassword("123456");
        
        Connection connection = connectionFactory.newConnection();
        Channel channel = connection.createChannel();
        
        String exchange = "test_dlx_exchange";
        String routingKey = "dlx.save";
        
        String msg = "Hello RabbitMQ DLX Message";
        
        for(int i =0; i<1; i ++){
            
            AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
                    .deliveryMode(2)
                    .contentEncoding("UTF-8")
                    .expiration("10000")
                    .build();
            channel.basicPublish(exchange, routingKey, true, properties, msg.getBytes());
        }
        
    }
}

消费者类

package com.bfxy.rabbitmq.api.dlx;

import java.util.HashMap;
import java.util.Map;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.QueueingConsumer;
import com.rabbitmq.client.QueueingConsumer.Delivery;

public class Consumer {

    
    public static void main(String[] args) throws Exception {
        
        
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("10.136.197.244");
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("/");
        connectionFactory.setUsername("admin");
        connectionFactory.setPassword("123456");
        
        Connection connection = connectionFactory.newConnection();
        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);
        
        //要进行死信队列的声明:
        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));
        
        
    }
}

自定义消费者类

package com.bfxy.rabbitmq.api.dlx;

import java.io.IOException;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;

public class MyConsumer extends DefaultConsumer {


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

    @Override
    public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
        System.err.println("-----------consume message----------");
        System.err.println("consumerTag: " + consumerTag);
        System.err.println("envelope: " + envelope);
        System.err.println("properties: " + properties);
        System.err.println("body: " + new String(body));
    }
}

死信队列的实现逻辑主要在消费者类中,正常的消息发送到交换机A上时,添加一个扩展参数:agruments.put("x-dead-letter-exchange", "dlx.exchange");
表示在发往A交换机时如果失败,则会发送到dlx.exchange交换机,即死信队列交换机
然后再声明死信队列交换机的队列和绑定关系,死信队列为dlx.queue
//进行死信队列的声明:

channel.exchangeDeclare("dlx.exchange", "topic", true, false, null);
channel.queueDeclare("dlx.queue", true, false, false, null);
channel.queueBind("dlx.queue", "dlx.exchange", "#");

至此即可实现发送到A交换机没有被成功消费的消息会自动发送到死信队列中。
业务系统可以根据实际场景再对死信队列的消息进行处理,可以进行手工处理,当然手工处理比较低端,其实是可以在程序中对死信队列的消息进行补偿处理。

相关文章

  • RabbitMQ学习(六)死信队列

    DLX:Dead-Letter-Exchange 当消息在一个队列中变成死信(dead message)之后,它能...

  • 【深度知识】RabbitMQ死信队列的原理及GO实现

    1. 摘要 本文按照以下目前讲解RabbitMQ死信队列的内容,包括:(1)死信队列是什么?(2)如何配置死信队列...

  • rabbitmq延迟队列

    一、讲解RabbitMQ的的死信队列+ TTL 二、RabbitMQ的延迟队列和应⽤场景 1、简介 2、业界的⼀些...

  • RabbitMQ之认识死信队列一

    前言 RabbitMQ 有个队列叫死信队列,死信队列可以做蛮多事的,比如可以让消息半个小时后消费,规定每天几点钟消...

  • RabbitMQ消息中间件技术精讲17 高级篇十 死信队列

    死信队列介绍 本文是《RabbitMQ精讲系列》中第十七:RabbitMQ消息中间件技术精讲17 高级篇十 死信队...

  • RabbitMQ死信队列

    死信队列介绍 死信队列:DLX(dead-letter-exchange) 利用DLX,当消息在一个队列中变成死信...

  • RabbitMQ死信队列

    什么是死信队列 当发生以下任何事件,那么消息将成为死信 消费者使用basic.reject或 basic.nack...

  • 死信队列 (rabbitMQ)

    转载:http://www.imooc.com/article/283645 1.什么是死信队列 想必有些小伙伴应...

  • RabbitMQ 死信队列

    死信队列 "死信"模式 指的是,当消费者不能处理接收到的消息时,将这个消息重新发布到另外一个队列中,等待重试或者人...

  • RabbitMQ死信队列

    SpringBoot 是为了简化 Spring 应用的创建、运行、调试、部署等一系列问题而诞生的产物,自动装配的特...

网友评论

      本文标题:RabbitMQ学习(六)死信队列

      本文链接:https://www.haomeiwen.com/subject/iyqzqqtx.html