一线大厂面试真题——RabbitMQ实现延迟队列的两种方式

本文详细介绍了两种在SpringBoot应用中实现延迟队列的方法:一种是通过rabbitMQ插件实现不阻塞的延迟队列,另一种是通过死信机制实现但可能存在阻塞。作者提供了详细的代码示例和注意事项。
摘要由CSDN通过智能技术生成

目录

方法一:通过插件实现

优点

实现

方法二:通过死信实现延迟队列

缺点

实现


方法一:通过插件实现

优点

        不阻塞的延迟队列

实现


 1、安装rabbitMQ延迟插件 ---> rabbitmq-delayed-message-exchange (高版本的rabbitMQ安装完插件之后无需重启)当出现添加交换机有如图所示的选项时,说明安装插件成功

 2、定义常量

   /**
     * 访客延迟队列
     */
    String VISITOR_DELAY_QUEUE ="yxb.visitor.delay.queue";
 
    /**
     * 访客延迟交换机
     */
    String VISITOR_DELAY_EXCHANGE = "yxb.visitor.delay.exchange";
 
    /**
     * 访客延迟消息路由key
     */
    String VISITOR_DELAY_ROUTE_KEY = "yxb.receive.visitor.delay.routeKey";

 3、创建延迟队列

/**
     * 访客延迟队列
     * @return
     */
    @Bean
    Queue visitorDelayQueue() {
        return new Queue(VISITOR_DELAY_QUEUE);
    }

4、创建延迟交换机

@Bean
    public CustomExchange visitorDelayExchange(){
        HashMap<String, Object> args = new HashMap<>();
        args.put("x-delayed-type","direct");
        return new CustomExchange(VISITOR_DELAY_EXCHANGE,"x-delayed-message",true,false,args);
    }

5、绑定延迟队列和交换机

   /**
     * 延迟队列绑定交换机
     * @param visitorDelayQueue 延迟队列
     * @param visitorDelayExchange 交换机
     * @return Binding
     */
    @Bean
    public Binding bindVisitorDelayExchange(@Qualifier("visitorDelayQueue") Queue visitorDelayQueue,
                                            @Qualifier("visitorDelayExchange") CustomExchange visitorDelayExchange){
        return BindingBuilder.bind(visitorDelayQueue).to(visitorDelayExchange).with(VISITOR_DELAY_ROUTE_KEY).noargs();
    }

 6、发送延迟消息

  rabbitTemplate.convertAndSend(mqMessage.getExchange(),mqMessage.getRoutingKey(),mqMessage, message -> {
                // 设置延迟毫秒值
                message.getMessageProperties().setDelay(delayTimes.intValue());
                return message;
            }, new CorrelationData(mqMessage.getId()));

 7、监听延迟队列

@Component
@AllArgsConstructor
@Slf4j
public class VisitorEventDrive {
    private final VisitorOrdersService visitorOrdersService;
 
    @RabbitHandler
    @RabbitListener(queues = MqConstant.VISITOR_DELAY_QUEUE)
    public void receiveEvent(Message message, Channel channel, MqMessage mqMessage){
        try {
            //doSomething
        } catch (Exception e) {
            e.toString();
        }
    }
}


方法二:通过死信实现延迟队列

缺点

        会存在阻塞的情况

实现


先向队列中发送一个60秒到期的消息,再往队列中发送一个30秒到期的消息.预想的是队列先执行30秒的消息,再执行60秒的消息.但是实际情况是60秒的消息会阻塞队列,导致先执行了60秒的消息,再执行30秒的消息.(延迟30秒的要求没有实现)

1、创建死信队列和转发队列

/**
     * 访客二维码死信队列
     * @return
     */
    @Bean
    Queue visitorTtlQueue() {
        return QueueBuilder
                .durable(MqConstant.VISITOR_TTL_QUEUE)
                // 配置到期后转发的交换
                .withArgument("x-dead-letter-exchange", MqConstant.VISITOR_DIRECT_EXCHANGE)
                // 配置到期后转发的路由键
                .withArgument("x-dead-letter-routing-key", MqConstant.TTL_CHANGE_ROUTE_KEY)
                .build();
    }
 
    /**
     * 访客二维码死信消息转发队列
     * @return 队列
     */
    @Bean
    public Queue visitorTtlChangeQueue(){
        return new Queue(VISITOR_TTL_CHANGE_QUEUE);
    }

2、创建直连交换机和延时交换机

/**
     * 访客直连交换机
     * @return 交换机
     */
    @Bean
    public DirectExchange visitorDirectExchange(){
        return new DirectExchange(VISITOR_DIRECT_EXCHANGE);
    }
 
 
    /**
     * 延时消息交换机配置
     * @return DirectExchange
     */
    @Bean
    DirectExchange messageTtlDirect() {
        return (DirectExchange) ExchangeBuilder.directExchange(MESSAGE_TTL_EXCHANGE).durable(true).build();
    }

3、绑定队列和交换机 

 
 
    /**
     * 死信队列绑定交换机
     * @param visitorTtlQueue 死信队列
     * @param messageTtlDirect 交换机
     * @return Binding
     */
    @Bean
    public Binding bindVisitorTtlDirectExchange(@Qualifier("visitorTtlQueue") Queue visitorTtlQueue,
                                            @Qualifier("messageTtlDirect") DirectExchange messageTtlDirect){
        return BindingBuilder.bind(visitorTtlQueue).to(messageTtlDirect).with(TTL_ROUTE_KEY);
    }
 
 
/**
     * 转发队列绑定交换机
     * @param visitorTtlChangeQueue
     * @param visitorDirectExchange
     * @return Binding
     */
    @Bean
    public Binding bindVisitorTtlChangeExchange(@Qualifier("visitorTtlChangeQueue") Queue visitorTtlChangeQueue,
                                         @Qualifier("visitorDirectExchange") DirectExchange visitorDirectExchange){
        return BindingBuilder.bind(visitorTtlChangeQueue).to(visitorDirectExchange).with(MqConstant.TTL_CHANGE_ROUTE_KEY);
    }

4、发送死信消息

rabbitTemplate.convertAndSend(mqMessage.getExchange(),mqMessage.getRoutingKey(),mqMessage, message -> {
                // 设置延迟毫秒值
                message.getMessageProperties().setExpiration(String.valueOf(delayTimes));
                return message;
            }, new CorrelationData(mqMessage.getId()));

5、监听转发队列

@Component
@AllArgsConstructor
@Slf4j
public class VisitorEventDrive {
 
    @RabbitHandler
    @RabbitListener(queues = MqConstant.VISITOR_TTL_CHANGE_QUEUE)
    public void receiveEvent(Message message, Channel channel, MqMessage mqMessage){
        try {
           //doSomeThing
            
        }catch (Exception e) {
            
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值