rabbitmq-消息時效與死信隊列

TTL:

當我們的信息過多時會導致隊列(queue)內存耗盡無法正常接收信息的情況,此時我們可以對部分非重要的信息設置時效性,超過指定時間還未被處理則queue自動丟棄該條消息,以確保queue內存不被佔滿。

/**
 * Created by py
 */
public class TTLProcuder {
    private static final String queue = "simple_queue";

    public static void main(String[] args) throws IOException, TimeoutException {
        Connection instance = RabbitUtils.getInstance();
        Channel channel = instance.createChannel();
        Map<String,Object> headers = new HashMap<>();
        headers.put("h1","123");
        headers.put("h2","456");
        /**
         * deliveryMode:2 表示消息持久化
         * contentEncoding:該信息的傳輸格式
         * headers:自定義的傳輸參數
         * expiration:失效時間 毫秒
         */
        AMQP.BasicProperties build = new AMQP.BasicProperties.Builder()
                .deliveryMode(2).contentEncoding("utf-8")
                .expiration("10000").headers(headers).build();
        for (int i = 0; i <5 ; i++) {
            String msg = "this is a message:"+i;
            /**
             * queue:在rabbit中已存在不需要再次聲明
             * false:未找到指定隊列就丟棄該條消息
             * build:對該條消息的自定義配置
             * todo 使用該種方式是針對當前發送的這條消息所做的配置,不是針對該隊列所做的配置
             */
            channel.basicPublish("",queue,false,build,msg.getBytes());
        }
        System.out.println("消息發送完成");
        channel.close();
        instance.close();
    }
}

上述代碼實現我們指定某一條消息的時效時長,現在我們設置隊列中所有的消息都在指定時間後失效。

/**
 * Created by py
 * 2020/5/2
 */
public class TTLProcuder {

    public static void main(String[] args) throws IOException, TimeoutException {
        Connection instance = RabbitUtils.getInstance();
        Channel channel = instance.createChannel();
        //該設置讓ttl-queue的所有消息都是20S後自動丟失
        Map<String,Object> arguments = new HashMap<>();
        arguments.put("x-message-ttl",20000);
        channel.queueDeclare("ttl-queue",true,false,false,arguments);
        for (int i = 0; i <5 ; i++) {
            String msg = "this is a message:"+i;
            channel.basicPublish("","ttl-queue",false,null,msg.getBytes());
        }
        System.out.println("消息發送完成");
        channel.close();
        instance.close();
    }
}

死信隊列:

上述說明爲防止queue的信息堆積過多導致無法接收信息時可以通過設置信息時效來控制,如果我們不想將這部分的信息完全丟棄我們可以通過配置死信隊列來處理。

消息在queueA中超過10s未被消費,按照設置應該自動刪除(消息只保留10S),此時通過配置死信隊列可實現將該條信息從queueA中移動到死信隊列中來,這樣既釋放了queueA的內存空間又保留了該條信息。

簡示圖:

代碼:

import com.example.springcloud.eurekaclinet1demo.uitl.RabbitUtils;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * 生產者
 * Created by py
 */
public class Producer {
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection instance = RabbitUtils.getInstance();
        Channel channel = instance.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());
        }
        System.out.println("消息發送完成");
        channel.close();
        instance.close();
    }
}
/**
 * 消費者
 * Created by py
 */
public class Consumer {

    public static void main(String[] args) throws IOException, TimeoutException {
        Connection instance = RabbitUtils.getInstance();
        Channel channel = instance.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", "#");
        DefaultConsumer defaultConsumer = new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                super.handleDelivery(consumerTag, envelope, properties, body);
                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));
                //消費者接收到消息,但是沒有正常處理,返回給rabbit。
                //配置死信隊列後該條信息也會推送到私信隊列中,而不會回到原有隊列中
                /**
                 * public void basicNack(long deliveryTag, boolean multiple, boolean requeue)
                 * deliveryTag: 該條消息的標識
                 * multiple: 多條消息還是單條消息;false:單條消息
                 * requeue:false;
                 */
                //channel.basicNack(envelope.getDeliveryTag(),false,false);
            }
        };
        channel.basicConsume(queueName, false, defaultConsumer);
        System.out.println("消費者已啓動");
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章