Spring Boot RabbitMq之延迟队列

一、何谓延迟队列?

顾名思义,延迟队列就是进入该队列的消息会被延迟消费的队列。而普通的队列,消息一旦进入队列就会被消费者立即消费。有些同学可能会思考,那延迟队列可以用来干什么,为什么要使用延迟队列以及该如何使用?接下来,笔者将会为同学们一一介绍,然后带领同学们一起进行实战演练。

二、延迟队列的应用场景

延迟队列的应用场景有很多,以下列举了最常用的几种:

  • 用户生成订单30分钟之后,如果还未支付订单则需要及时的取消订单。
  • 当用户注册成功之后,过一分钟然后给用户发送短信注册提示以及邮箱注册提示。

有些同学在此刻可能会有一些疑虑。上面两种场景通过定时器也可以实现,而且非常的简单,也不用去维护RabbitMq,为什么还要使用延迟队列?不可否认,定时器是可以实现上面的场景,但是熟悉定时器同学们肯定知道,定时器是通过不断的轮询的方式实现的,这种做法十分的不优雅,而且还会存在及时性的问题。说了这么多定时器实现的诸多缺点,那RabbitMq又是如何实现的,会不会有同样的问题?在下文,笔者将会为同学们详细的介绍。

三、如何实现延迟队列?

通过上文,笔者相信同学们对延迟队列也有了一定的了解。接下来,笔者将带领同学们进行实战演练。实现延迟队列的方式有以下两种:

  • 通过消息过期后进入死信交换机,再由交换机转发到延迟消费队列,实现延迟功能。
  • 使用rabbitmq-delayed-message-exchange插件实现延迟功能。

在实际开发中,通常情况下都会使用RabbitMq插件实现延迟队列。因此,笔者在本文会详细的介绍第二种实现方式。有兴趣的同学可以尝试实践第一种。
在开始实战之前,笔者默认同学们都已经安装好了RabbitMq。

1.1 下载插件

打开官网下载:http://www.rabbitmq.com/community-plugins.html
这里应该选择与RabbitMq相对应的版本进行下载。(注意:此插件只适应于RabbitMQ 3.5.7及以上的版本,依赖Erlang/OPT 18.0及以上运行环境)

1.2 安装插件

  • 上传下载的文件至linux服务器,然后解压下载的插件:
    unzip rabbitmq_delayed_message_exchange-20171215-3.6.x.zip
  • 复制插件到RabbitMq的plugins目录下:
    sudo cp -r rabbitmq_delayed_message_exchange-20171215-3.6.x /usr/lib/rabbitmq/lib/rabbitmq_server-3.6.6/plugins
  • 关闭RabbitMQ服务,然后启动延时插件:
    rabbitmq-plugins enable rabbitmq_delayed_message_exchange
  • 到这一步,RabbitMq的延时插件已经安装完毕

1.3 代码实现

讲了这么多理论知识,想必某些同学已经迫不及待的想要看代码。接下来,笔者就开始满足同学们的要求,开始上代码。

  • 配置启动类

     @SpringBootApplication
     @EnableRabbit
     class RabbitMqApplication {
     	public static void main(String[] args) {
         	SpringApplication.run(RabbitMqApplication.class, args);
     	}
     }
    
  • 配置队列

     @Configuration
     public class RabbitMqConfig {    	
     	
     	public final static String DELAYED_QUEUE_NAME = "delayed.order";
          
          public final static String EXCHANGE_NAME = "delayed_exchange";	     
          
          public final static String DELAY_ORDER_ROUTING_KEY = "delay_order_routing_key";
          
          @Bean
          public Queue queue() {
              return new Queue(DELAYED_QUEUE_NAME);
          }
          // 配置默认的交换机
          @Bean
          CustomExchange customExchange() {
              Map<String, Object> args = new HashMap<>();
              args.put("x-delayed-type", "direct");
              //参数二为类型:必须是x-delayed-message
              return new CustomExchange(EXCHANGE_NAME, "x-delayed-message", true, false, args);
          }
          // 绑定队列到交换器
          @Bean
          Binding binding() {
              return BindingBuilder.bind(queue()).to(customExchange()).with(DELAY_ORDER_ROUTING_KEY).noargs();
          }
      }
    
  • 发送消息

      @Slf4j
      public class RabbitMqSender {	
     	  @Autowired 	
     	  private RabbitTemplate rabbitTemplate;	 
          public static void senderDelayedOrderOutTradeNo(RabbitTemplate rabbitTemplate, String outTradeNo, Integer second) {
              
              rabbitTemplate.convertAndSend(RabbitMqConfig.EXCHANGE_NAME, RabbitMqConfig.DELAY_ORDER_ROUTING_KEY, outTradeNo, message -> {
    
              message.getMessageProperties().setHeader("x-delay", second.intValue()*1000);
              log.info("send message: " + outTradeNo);
              return message;
          
         	 });
       	   }
       }
    
  • 消费消息

     @Component
     @Slf4j
     public class DelayedOrderReceiver {	
         @RabbitListener(queues = RabbitMqConfig.DELAYED_QUEUE_NAME)
         @RabbitHandler
         public void process(String outTradeNo) {
             log.info("接受时间: " +  new Date());
             log.info("Fetch order id from rabbit mq: " + outTradeNo);
             //在这里可以加入业务逻辑,比如: 修改还支付订单的状态;
         }
     }
    
  • 测试延迟队列

       @Slf4j
       @RequestMapping("/api/rabbitmq")	
       @RestController	
       public class RabbitMqController {	
     	  public static final int THIRD_SECOND = 3;
           @Autowired
           private RabbitTemplate rabbitTemplate;
       
           @PostMapping("/senderDelayedOrder")
           public void senderDelayedOrder() {
               log.info("发送时间: "  + new Date());
               RabbitMqSender.senderDelayedOrderOutTradeNo(rabbitTemplate, "订单号", THIRD_SECOND);
           }
        }
    
  • 测试结果

     发送时间: Mon Jan 28 18:48:18 CST 2019
     Send message:订单号
     接受时间: Mon Jan 28 18:48:21 CST 2019
     Fetch message:订单号
    

通过测试结果可以看出,在消息发送3秒后,消费者如我们所期望的的接受到了消息。实践证明,我们的延迟队列已经成功实现。

四、总结及回顾

笔者通过本文主要给同学们介绍了什么是延迟对列,以及延迟队列的使用场景,同时也和同学们一起完成了RabbitMq延迟队列的实战演练。建议大家按照本文的步骤动手试一下,肯定会有新的收获。如果遇到不懂问题,可以联系笔者一起探讨。最后祝大家学习开心,生活愉快!

  • 9
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值