MQ(消息队列)之rabbitmq的消息ttl和死信路由

消息的TTL(Time To Live)就是消息的存活时间。RabbitMQ可以对队列和消息分别设置TTL。

对队列设置没有消费者消费的保留时间,也可以对每一个单独的消息做单独的设置。

超过了这个时间,就认为这个消息死了,称之为死信

如果队列设置了,消息也设置了,那么会取小的。所以一个消息如果被路由到不同的队列中,这个消息的死亡时间有可能不一样(不同的队列设置)。

死信路由DLX(Dead Letter Exchange):一个消息在满足如下条件下,会进死亡路由:

1. 一个消息被consumer拒收了,并不会再次被其他消费者使用
2. 消息的ttl到了,消息过期了
3. 队列的长度限制满了。排在前面的消息会被丢弃或者扔到死信路由上

DLX其实就是一种普通的exchange,和创建其他的exchange没有两样。只是在某一个设置Dead Letter Exchanger的队列中有消息过期了,会自动触发消息的转发,发送到DLX中去。

我们既可以控制消息在一段时间后变成死信,又可以控制消息变成死信,并被路由到某一个指定的交换机,结合二者,其实就可以实现一个延时队列 。

声明死信队列的方式,使用如下参数:
 

arguments.put("x-dead-letter-exchange", "dlx名称");

arguments.put("x-dead-letter-routing-key", "routingkey");

arguments.put("x-message-ttl", "过期时间"); 

以定时关闭订单为例:

  1. 订单创建成功,发送消息到创建订单的路由

  2. 创建订单的路由转发消息给延时队列,延时队列的延时时间就是订单从创建到支付过程,允许的最大等待时间。延时队列不能有消费者(即消息不能被消费)

  3. 延时时间一到,消息被转入DLX(死信路由)

  4. 死信路由把死信消息转发给死信队列

  5. 订单系统监听死信队列,获取到死信消息后,执行关单解库存操作

配置延时队列:

@EnableRabbit
@Configuration
public class RabbitMqConfig {

    /**
     * 交换机
     * @return
     */
    @Bean
    public Exchange exchange(){

        return new TopicExchange("ORDER-EXCHANGE", true, false, null);
    }

    /**
     * 延时队列
     * @return
     */
    @Bean("ORDER-TTL-QUEUE")
    public Queue ttlQueue(){

        Map<String, Object> arguments = new HashMap<>();
        arguments.put("x-dead-letter-exchange", "ORDER-EXCHANGE");
        arguments.put("x-dead-letter-routing-key", "order.close");
        arguments.put("x-message-ttl", 120000); // 仅仅用于测试,实际根据需求,通常30分钟或者15分钟
        return new Queue("ORDER-TTL-QUEUE", true, false, false, arguments);
    }

    /**
     * 延时队列绑定到交换机
     * rountingKey:order.create
     * @return
     */
    @Bean("ORDER-TTL-BINDING")
    public Binding ttlBinding(){

        return new Binding("ORDER-TTL-QUEUE", Binding.DestinationType.QUEUE, "ORDER-EXCHANGE", "order.create", null);
    }

    /**
     * 死信队列
     * @return
     */
    @Bean("ORDER-CLOSE-QUEUE")
    public Queue queue(){

        return new Queue("ORDER-CLOSE-QUEUE", true, false, false, null);
    }

    /**
     * 死信队列绑定到交换机
     * routingKey:order.close
     * @return
     */
    @Bean("ORDER-CLOSE-BINDING")
    public Binding closeBinding(){

        return new Binding("ORDER-CLOSE-QUEUE", Binding.DestinationType.QUEUE, "ORDER-EXCHANGE", "order.close", null);
    }
}

测试死信队列:

@RunWith(SpringRunner.class)
@SpringBootTest
public class GmallOmsApplicationTests {

    @Autowired
    private AmqpTemplate amqpTemplate;

    @Test
    public void contextLoads() {

        this.amqpTemplate.convertAndSend("ORDER-EXCHANGE", "order.create", "hello world!");
    }

}

创建死信监听:

@Component
public class DeadListener {

    @RabbitListener(queues = "ORDER-CLOSE-QUEUE")
    public void testDead(String msg){
        System.out.println(msg);
    }
}

样例流程图:

发布了126 篇原创文章 · 获赞 6 · 访问量 3724

猜你喜欢

转载自blog.csdn.net/qq_40244391/article/details/104382873