淘宝七天自动确认收货,怎么设计?RabbitMQ延迟队列,消息延迟推送delayed_message入门教程!

本文介绍了如何利用RabbitMQ的延迟队列插件rabbitmq_delayed_message_exchange实现消息延迟推送,以模拟淘宝购物后七天自动确认收货的系统功能。通过配置延迟队列,避免了传统方法如数据库轮询和Redis的性能瓶颈,确保系统高效运行。详细步骤包括插件安装、消息队列配置、消费端监听以及发送延迟消息的示例代码演示。
摘要由CSDN通过智能技术生成

#淘宝七天自动确认收货,让你实现,怎么设计?

目前非常多应用软件都有消息延迟推送的需求,例如:

  • 淘宝购物在我们签收商品后,如不点击收货确认,系统会在七天后自动确认收货,并通知支付系统打款给商家,这个过程持续七天。
  • 物联网系统定时向终端下发命令,如果一段时间没有应答,就需要将终端设置为超时。
  • 12306购票支付确认页面。我们选好票点击确认跳转到支付页面,倒计时30分钟如果不支付则会自动取消订单。其实在下单的那一刻系统就发送一个延时消息,时效30分钟,如果30分钟内支付订单,则不取消订单,如没有支付,则取消订单。

上述场景,如使用传统方法,无疑将大大降低系统整体性能和吞吐量:

  • 使用传统数据库轮询来判断数据库表中订单状态,这大大增加IO次数,性能极低。
  • 使用Redis给订单设置过期时间,最后判断Redis中是否还有该订单来决定订单是否生效。这种解决方案比数据库轮询效率高,但低于消息延迟推送,因为Redis存储于内存中,数据量较大、恶意刷单等情况会给系统带来巨大冲击。
  • 使用JVM原生DelayQueue,同样会占用大量内存,且没有持久化策略,一旦重启或宕机,则数据丢失。

#RabbitMQ延迟队列实现消息延迟推送功能

RabbitMQ3.6前可采用死信队列+TTL。

RabbitMQ3.6后,官方提供了rabbitmq_delayed_message_exchange延迟队列插件,本文采取这种方式。 

#Rabbitmq_delayed_message_exchange插件下载安装

RabbitMQ插件放到根目录的plugins文件夹下,如D:\Program Files\RabbitMQ\rabbitmq_server-3.9.5\plugins。

RabbitMQ下载安装及基础教程可参考上一篇文章:淘宝购买商品后系统如何处理?认识消息服务之RabbitMQ基础,打造Direct、Fanout、Topic三种消息队列。(精选长文)_m0_59562547的博客-CSDN博客当我们在淘宝购买商品后,系统会如何处理呢?传统项目,我们一般会进行如下操作:同步发送订单到商家。同步在数据库中扣减库存。更新缓存使前后端数据一致。而面对淘宝这样超级用量的系统,我们如果采用传统项目模式,会出现如下问题:一个订单需求会调用支付、库存、缓存、订单等多个系统或者模块,相互之间的调用多而复杂,维护起来非常繁琐。(解决办法:解耦,降低系统耦合度)同步执行支付、库存、缓存、订单多个系统,总耗时为上述系统执行的总时长。一个系统卡壳会影响整个执行效率,稳定性弱,效率低。(解决办法:https://blog.csdn.net/m0_59562547/article/details/120412657

①将rabbitmq_delayed_message_exchange-3.9.0.ez下载到plugins文件夹下,安装后也不能删除。

官方下载地址:Releases · rabbitmq/rabbitmq-delayed-message-exchange · GitHub 

② 双击RabbitMQ Command Prompt (sbin dir)或CMD到RabbitMQ的sbin目录中,输入rabbitmq-plugins enable rabbitmq_delayed_message_exchange安装延时队列插件。

③启动RabbitMQ,通过网址http://localhost:15672/ 进入登录界面(前提开启WEB管理插件,参考上一篇文章),可见Exchanges中新增加了一种全新的队列x-delayed-message,安装成功!

#RabbitMQ消息延迟推送delayed_message代码实现

①Maven依赖及application.propertie基础配置可参考上一篇文章:

淘宝购买商品后系统如何处理?认识消息服务之RabbitMQ基础,打造Direct、Fanout、Topic三种消息队列。(精选长文)_m0_59562547的博客-CSDN博客

②配置消息延迟队列,在TopicExchange交换机声明中设置exchange.setDelayed(true)来开启延迟队列。

package com.example.demohelloworld.RabbitMq.Lazy;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitLazyConfig {
    public final static String lazyname="my-lazyname";
    @Bean
    TopicExchange topicExchangeLazy(){
        TopicExchange exchange= new TopicExchange(lazyname,true,false);
        exchange.setDelayed(true);//开启延时队列
        return exchange;
    }
    @Bean
    Queue queueLazy(){
        return new Queue("lazy");
    }
    @Bean
    Binding bindingLazy(){
        return BindingBuilder.bind(queueLazy())
                .to(topicExchangeLazy())
                .with("lazy.#");
    }
}

也可以声明通用交换机CustomExchange,type类型为x-delayed-message,消息类型args设置为("x-delayed-type","topic")来开启延迟队列。setDelayed(true)底层也是通过这种方式来实现的。TopicExchange和CustomExchange两种方式二选一,源码参考如下:

    @Bean
    CustomExchange customExchange() {
        Map<String, Object> args = new HashMap<>();
        args.put("x-delayed-type", "topic");
        return new CustomExchange(lazyname,"x-delayed-message", true, false, args);
    }
    @Bean
    Queue queueLazy(){
        return new Queue("lazy");
    }
    @Bean
    BindingBuilder.GenericArgumentsConfigurer binding() {
        return BindingBuilder.bind(queueLazy())
                .to(customExchange())
                .with("lazy.#");
    }

③配置消息消费端,因为是精简代码,所以暂时不含有Confirm和Returns监听,如需要可参看上一篇文章。我们配置一个"lazy"队列监听,指定一个消息消费方法logger日志输出,将所接收到的消息内容在后台输出(生产环境中则为具体执行的业务逻辑,比如淘宝订单消息消费逻辑,自动确认收货;12306订单消息消费逻辑,关闭订单)。

package com.example.demohelloworld.RabbitMq.Lazy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class RabbitLazyService {
    Logger logger= LoggerFactory.getLogger(this.getClass());
    @RabbitListener(queues = "lazy")
    public void Handler(Message message)throws IOException{
        logger.info("LazyReceiverHandler:"+ new String(message.getBody()));
    }
}

④配置实现类来模拟5秒钟后执行延迟队列,CorrelationData是传入方法执行时的时间戳,声明消息处理类MessagePostProcessor是通过Message->对象的Header属性来设置消息延迟时间,这里我们采用了lamda写法,setHeader("x-delay",5000)表明这是一个延迟推送队列,时间为5秒。

rabbitTemplate.convertAndSend中分别写入交换机名称,队列名称,消息内容、消息处理类MessagePostProcessor以及方法执行时间戳CorrelationData。

package com.example.demohelloworld.RabbitMq.Lazy;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
@RestController
public class RabbitLazyController {
    @Autowired
    RabbitTemplate rabbitTemplate;
    @GetMapping("/lazy")
    public void lazy(){
        CorrelationData correlationData=new CorrelationData("12345678909"+new Date());
        MessagePostProcessor messagePostProcessor= message -> {
            message.getMessageProperties().setHeader("x-delay",5000);
            return message;
        };
        rabbitTemplate.convertAndSend(RabbitLazyConfig.lazyname,"lazy.send","hello lazy!",messagePostProcessor,correlationData);
    }
}

⑤最后启动项目开始测试,打开浏览器输入http://localhost:8080/lazy,等待5秒钟后,我们收到了消息消费端发来的消息。

#总结 

回到最开始的问题,当我们在淘宝下单签收商品后,立即生成时间为七天的延时消息队列,在这七天内,如果不点击收货确认,系统会在七天后自动推送消息使订单确认收货并通知支付系统打款给商家,如已经点击收货确认,则该延时消息队列失效。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值