Fila de mensagens mortas do RabbitMQ 11

fila de letras mortas

Visão geral

Se não houver consumidor para processar os dados na fila de mensagens, ele sempre ocupará o espaço da fila de mensagens.

Por exemplo, no cenário de retirada de passagem, depois que um usuário fizer um pedido de uma passagem de trem de alta velocidade, ele pegará um assento e efetuará o pagamento. No entanto, se o usuário não pagar a tempo após fazer o pedido , o ingresso não pode ser ocupado por este usuário o tempo todo, pois será ocupado por outros. Você não pode mais comprar este ingresso, então ele expirará após um período de tempo, permitindo que este ingresso continue a ser adquirido por outros .

Neste momento, você pode usar a fila de devoluções para processar ainda mais os pedidos que o usuário não pagou ao longo do tempo ou que o usuário cancelou ativamente.

Então, como construir esse modelo de uso? Na verdade, é essencialmente uma troca de letras mortas + fila de letras mortas .

Quando uma mensagem na fila normal é determinada como uma mensagem morta, ela será enviada para o switch de mensagens mortas correspondente e, em seguida, enviada para a fila de mensagens mortas através do switch.A fila de mensagens mortas também tem um consumidor correspondente para processar o mensagem.

Geralmente há três situações em que uma letra morta é considerada morta:

  • A mensagem foi rejeitada ( basic.reject/ basic.nack) e requeue = false.
  • A mensagem expirou e não foi consumida.
  • A fila de mensagens atingiu seu tamanho máximo.

gerar letras mortas

Mensagem rejeitada

  1. Crie um novo switch de mensagens não entregues e uma fila de mensagens não entregues na classe de configuração e vincule-os.

    import org.springframework.amqp.core.Binding;
    import org.springframework.amqp.core.BindingBuilder;
    import org.springframework.amqp.core.Exchange;
    import org.springframework.amqp.core.ExchangeBuilder;
    import org.springframework.amqp.core.Queue;
    import org.springframework.amqp.core.QueueBuilder;
    import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    /**
     * RabbitMQ配置类
     */
    @Configuration
    public class RabbitMqConfig {
    
        ...
    
        /**
         * 定义消息队列
         * @return 消息队列对象
         */
        @Bean("testQueue")
        public Queue queue(){
            return QueueBuilder
                    // 非持久化类型
                    .nonDurable("test_springboot")
                    // 指定死信交换机
                    .deadLetterExchange("dl.direct")
                    // 指定死信RoutingKey
                    .deadLetterRoutingKey("dl_test_springboot_key")   
                    .build();
        }
    
        /**
         * 构建死信交换机
         * @return 死信交换机
         */
        @Bean
        public Exchange dlExchange(){
            // 创建一个新的死信交换机
            return ExchangeBuilder.directExchange("dl.direct").build();
        }
    
        /**
         * 构建死信队列
         * @return 死信队列
         */
        @Bean
        public Queue dlQueue(){
            return QueueBuilder
                    .nonDurable("dl_test_springboot")
                    .build();
        }
    
        /**
         * 死信交换机和死信队列绑定
         * @param exchange 死信交换机
         * @param queue 死信队列
         * @return 绑定对象
         */
        @Bean
        public Binding dlBinding(@Qualifier("dlExchange") Exchange exchange,
                                 @Qualifier("dlQueue") Queue queue){
            return BindingBuilder
                    .bind(queue)
                    .to(exchange)
                    .with("dl_test_springboot_key")
                    .noargs();
        }
        
        ...
        
    }
  2. Ouça as mensagens da fila normal e da fila de mensagens não entregues.

    import cn.codesail.rabbitmq.entity.User;
    import com.rabbitmq.client.Channel;
    import org.springframework.amqp.rabbit.annotation.RabbitListener;
    import org.springframework.amqp.support.AmqpHeaders;
    import org.springframework.messaging.handler.annotation.Header;
    import org.springframework.stereotype.Component;
    
    /**
     * 直连队列监听器
     */
    @Component
    public class DirectListener {
    
        /**
         * 监听正常队列消息
         */
        @RabbitListener(queues = "test_springboot", messageConverter = "jackson2JsonMessageConverter")
        public void receiver(Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag, User user) throws Exception {
            // 拒绝消息。第二个参数为true则消息返回队列,第二个参数为false则消息不返回队列,成为死信
            channel.basicReject(deliveryTag, false);
            System.out.println("正常队列接收到消息:" + user);
        }
        
        /**
         * 监听死信队列消息
         */
        @RabbitListener(queues = "dl_test_springboot", messageConverter = "jackson2JsonMessageConverter")
        public void receiverDl(User user) {
            System.out.println("死信队列接收到消息:" + user);
        }
    }

    Se o ouvinte de mensagens da fila normal rejeitar a mensagem e não devolvê-la à fila, ela se tornará uma mensagem morta e será recebida pelo ouvinte da fila de mensagens mortas.

  3. Exclua a fila original. A fila vinculada à fila de devoluções só pode ser criada após a fila original ser excluída.

  4. Implementar produtores.

    import cn.codesail.rabbitmq.entity.User;
    import org.junit.jupiter.api.Test;
    import org.springframework.amqp.rabbit.core.RabbitTemplate;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    
    @SpringBootTest
    class RabbitMqSpringBootTests {
    
        /**
         * RabbitTemplate封装了大量的RabbitMQ操作,已经由Starter提供,因此直接注入使用即可
         */
        @Autowired
        private RabbitTemplate rabbitTemplate;
    
        /**
         * 生产者
         */
        @Test
        void producer() {
            
            // 发送Json消息
            User user = new User();
            user.setName("张三");
            user.setAge(18);
            rabbitTemplate.convertAndSend("amq.direct", "test_springboot_key", user);
        }
    
    }
  5. Inicie o produtor para enviar mensagens:

    Como você pode ver, a fila de mensagens não entregues recebeu a mensagem.

A mensagem expirou e não foi consumida

  1. Defina o valor TTL da fila.

    import org.springframework.amqp.core.Queue;
    import org.springframework.amqp.core.QueueBuilder;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    /**
     * RabbitMQ配置类
     * 
     * @author CodeSail
     */
    @Configuration
    public class RabbitMqConfig {
    
        ...
    
        /**
         * 定义消息队列
         * @return 消息队列对象
         */
        @Bean("testQueue")
        public Queue queue(){
            return QueueBuilder
                    // 非持久化类型
                    .nonDurable("test_springboot")
                    // 指定死信交换机
                    .deadLetterExchange("dl.direct")
                    // 指定死信RoutingKey
                    .deadLetterRoutingKey("dl_test_springboot_key")
                    // 如果5秒没处理,就自动删除
                    .ttl(5000)
                    .build();
        }
    
        ...
    }
  2. Cancele a escuta normal da fila.

    import cn.codesail.rabbitmq.entity.User;
    import com.rabbitmq.client.Channel;
    import org.springframework.amqp.rabbit.annotation.RabbitListener;
    import org.springframework.amqp.support.AmqpHeaders;
    import org.springframework.messaging.handler.annotation.Header;
    import org.springframework.stereotype.Component;
    
    /**
     * 直连队列监听器
     */
    @Component
    public class DirectListener {
    
        /**
         * 监听正常队列消息
         */
    //    @RabbitListener(queues = "test_springboot", messageConverter = "jackson2JsonMessageConverter")
    //    public void receiver(Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag, User user) throws Exception {
    //        // 拒绝消息。第二个参数为true则消息返回队列,第二个参数为false则消息不返回队列,成为死信
    //        channel.basicReject(deliveryTag, false);
    //        System.out.println("正常队列接收到消息:" + user);
    //    }
        
        /**
         * 监听死信队列消息
         */
        @RabbitListener(queues = "dl_test_springboot", messageConverter = "jackson2JsonMessageConverter")
        public void receiverDl(User user) {
            System.out.println("死信队列接收到消息:" + user);
        }
    }
  3. Implementar produtores.

    import cn.codesail.rabbitmq.entity.User;
    import org.junit.jupiter.api.Test;
    import org.springframework.amqp.rabbit.core.RabbitTemplate;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import java.util.concurrent.TimeUnit;
    
    @SpringBootTest
    class RabbitMqSpringBootTests {
    
        /**
         * RabbitTemplate封装了大量的RabbitMQ操作,已经由Starter提供,因此直接注入使用即可
         */
        @Autowired
        private RabbitTemplate rabbitTemplate;
    
        /**
         * 生产者
         */
        @Test
        void producer() throws InterruptedException {
            
            // 发送Json消息
            User user = new User();
            user.setName("张三");
            user.setAge(18);
            rabbitTemplate.convertAndSend("amq.direct", "test_springboot_key", user);
        }
    
    }
  4. Exclua a fila original. Somente depois de excluir a fila original você poderá criar uma fila com um TTL vinculado à fila de devoluções.

  5. Inicie o serviço e ouça as mensagens.

  6. Inicie o produtor para enviar mensagens e aguarde 5 segundos:

    Como você pode ver, a fila de mensagens não entregues recebeu a mensagem.

A fila de mensagens atinge o comprimento máximo

  1. Defina o comprimento máximo da mensagem da fila.

    import org.springframework.amqp.core.Binding;
    import org.springframework.amqp.core.BindingBuilder;
    import org.springframework.amqp.core.Exchange;
    import org.springframework.amqp.core.ExchangeBuilder;
    import org.springframework.amqp.core.Queue;
    import org.springframework.amqp.core.QueueBuilder;
    import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    /**
     * RabbitMQ配置类
     */
    @Configuration
    public class RabbitMqConfig {
    
        ...
    
        /**
         * 定义消息队列
         * @return 消息队列对象
         */
        @Bean("testQueue")
        public Queue queue(){
            return QueueBuilder
                    // 非持久化类型
                    .nonDurable("test_springboot")
                    // 指定死信交换机
                    .deadLetterExchange("dl.direct")
                    // 指定死信RoutingKey
                    .deadLetterRoutingKey("dl_test_springboot_key")
                    // 最大长度设定为3
                    .maxLength(3)
                    .build();
        }
    
        ...
        
    }
  2. Cancele a escuta normal da fila.

    import cn.codesail.rabbitmq.entity.User;
    import org.springframework.amqp.rabbit.annotation.RabbitListener;
    import org.springframework.stereotype.Component;
    
    /**
     * 直连队列监听器
     */
    @Component
    public class DirectListener {
    
        /**
         * 监听正常队列消息
         */
    //    @RabbitListener(queues = "test_springboot", messageConverter = "jackson2JsonMessageConverter")
    //    public void receiver(User user) {
    //        System.out.println("正常队列接收到消息:" + user);
    //    }
        
        /**
         * 监听死信队列消息
         */
        @RabbitListener(queues = "dl_test_springboot", messageConverter = "jackson2JsonMessageConverter")
        public void receiverDl(User user) {
            System.out.println("死信队列接收到消息:" + user);
        }
    }
  3. Exclua a fila original. Somente após a fila original ser excluída é que uma fila com um comprimento máximo definido que está vinculada à fila de devoluções pode ser criada.

  4. Defina produtor.

    import cn.codesail.rabbitmq.entity.User;
    import org.junit.jupiter.api.Test;
    import org.springframework.amqp.rabbit.core.RabbitTemplate;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import java.util.concurrent.TimeUnit;
    
    @SpringBootTest
    class RabbitMqSpringBootTests {
    
        /**
         * RabbitTemplate封装了大量的RabbitMQ操作,已经由Starter提供,因此直接注入使用即可
         */
        @Autowired
        private RabbitTemplate rabbitTemplate;
    
        /**
         * 生产者
         */
        @Test
        void producer() throws InterruptedException {
            
            for (int i = 0; i < 4; i++) {
                User user = new User();
                user.setName("张三" + i);
                user.setAge(18);
                rabbitTemplate.convertAndSend("amq.direct", "test_springboot_key", user);
            }
        }
    
    }
  5. Inicie o produtor para enviar mensagens.

    Como você pode ver, o primeiro elemento da fila é eliminado e se torna letra morta.

    A fila é semelhante a um pipeline: quando o pipeline estiver cheio, a última pessoa a entrar expulsará a primeira.


Acho que você gosta

Origin blog.csdn.net/qq_37770674/article/details/130097887
Recomendado
Clasificación