Springboot 2.x integrates Rabbitmq to realize delayed consumption

Preface

For example, when we use mq, we don't want to receive the message immediately. For example, we can query the order after 3 minutes. At this time, we need to use the delayed message to send.

How does RabbitMQ implement late queues?

The AMQP protocol and RabbitMQ queue itself do not directly support the delay queue function. But we can use the two characteristics of RabbitMQ to curve the delay queue:

特性1、Time To Live(TTL)

1.RabbitMQ can set x-expires for Queue

2. Set x-message-ttl for Message

Through these two ways to control the lifetime of the message

  • If set by the queue properties, all messages in the queue have the same expiration time.
  • If the messages are individually set, the TTL of each message can be different.
  • If it expires (both are set at the same time, the first expiration time shall prevail), the message becomes a dead letter (dead letter)

特性2、Dead Letter Exchanges(DLX)

RabbitMQ's Queue can be configured with x-dead-letter-exchange and x-dead-letter-routing-key (optional) two parameters. If a dead letter appears in the queue, it will be rerouted and forwarded to the specified according to these two parameters. queue.

  • x-dead-letter-exchange: resend the dead letter to the designated exchange after the dead letter appears
  • x-dead-letter-routing-key: After the dead letter appears, the dead letter will be sent again according to the specified routing-key

The dead letter in the queue includes:

  • The TTL of the message or queue expired
  • The queue reaches the maximum length
  • The message was rejected by the consumer (basic.reject or basic.nack) and requeue=false

Combining the above two features, after setting the TTL rule, when a message becomes a dead letter in a queue, it can be re-forwarded to another Exchange or Routing Key using the DLX feature, and the message can be consumed again.

method one:

    /死信队列的应用//

    /**
     * DLX测试队列
     */
    @Bean
    public Queue DLXTestQueue() {
        Map<String, Object> args = new HashMap<>(2);
        args.put("x-dead-letter-exchange", "DL_exchange");
        args.put("x-dead-letter-routing-key", "DL_queue");
        return QueueBuilder.nonDurable("DLX-test-queue").withArguments(args).build();
    }

    @Bean
    public Exchange DLXTestExchange() {
        return ExchangeBuilder.directExchange("DLX-test-exchange").durable(true).build();
    }

    @Bean
    public Binding DLXTestBinding() {
        return new Binding("DLX-test-queue", Binding.DestinationType.QUEUE, "DLX-test-exchange", "DLX-test-queue", null);
    }


    ///声明一个死信队列,交换机,绑定//
    @Bean
    public Queue dlQueue() {
        return QueueBuilder.nonDurable("DL_queue").build();
    }

    @Bean
    public Exchange dlExchange() {
        return ExchangeBuilder.directExchange("DL_exchange").durable(true).build();
    }

    /**
     * 死信路由通过 DL_queue 绑定键绑定到死信队列上.
     */
    @Bean
    public Binding deadLetterBinding() {
        return new Binding("DL_queue", Binding.DestinationType.QUEUE, "DL_exchange", "DL_queue", null);
    }

send:

    /**
     * 测试死信队列
     */
    @GetMapping("ttl")
    public Resp testTTL() {
        rabbitTemplate.convertAndSend("DLX-test-exchange", "DLX-test-queue", "去私信队列", messagePostProcessor -> {
            messagePostProcessor.getMessageProperties().setExpiration("10000");
            return messagePostProcessor;
        });
        return Resp.success("ok", null);
    }

 consumer:

    @RabbitListener(queues = {"DL_queue"})
    public void DLXTestQueue(Message message, Channel channel) throws IOException {
        log.info("死信队列  10s 后 消费消息 {}", new String(message.getBody()));
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }

Method 2: Rabbitmq 3.5.7 and above provides a plug-in (rabbitmq-delayed-message-exchange) to realize the delayed queue function. At the same time, the plugin depends on Erlang/OPT 18.0 and above.

Plug-in download address: https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases , please refer to my last article for details .

Configuration:

package com.zoo.mq.config;

import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

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


/**
 * @author: 谢飞
 */
@Configuration
public class RabbitMqConfig {

    /**
     * 定义延迟消息发送的队列.
     */
    @Bean
    public Queue delayQueue() {
        return QueueBuilder.nonDurable("delay_queue").build();
    }


    /交换机/

    /**
     * 定义一个用于延迟消息发送的交换机
     * 延时队列交换机 注意这里的交换机类型:CustomExchange
     */
    @Bean
    public CustomExchange delayExchange() {
        Map<String, Object> args = new HashMap<>();
        args.put("x-delayed-type", "direct");
        return new CustomExchange("delay_exchange", "x-delayed-message", true, false, args);
    }


    绑定/

    /**
     * 给延时队列绑定交换机
     */
    @Bean
    public Binding redirectBinding() {
        return BindingBuilder.bind(delayQueue()).to(delayExchange()).with("delay_key").noargs();
    }

}

Producer:

    @GetMapping("sendTTL")
    public Resp sendTTL() {
        rabbitTemplate.convertAndSend("delay_exchange", "delay_key", "hello", messagePostProcessor -> {
            messagePostProcessor.getMessageProperties().setDelay(10000);
            return messagePostProcessor;
        });
        return Resp.success("ok", null);
    }

 consumer:

    @RabbitListener(queues = {"delay_queue"})
    public void delayQueue(Message message, Channel channel) throws IOException {
        log.info("delay_queue  10s 后 消费消息 {}", new String(message.getBody()));
    }

Test ok. 

The number of messages sent to the queue when using the rabbitmq-delayed-message-exchange plug-in may not be visible in the web management interface and does not affect normal function use

 

 

Guess you like

Origin blog.csdn.net/qq_36850813/article/details/103279801