分布式系统延时任务方案

在实际项目开发中,我们遇到了如下需求:

1,机票订单下单后,如果30分钟内未支付,则自动取消

2,产品上架后,24小时都没有人买,则自动下架

3,一定时间后自动评价或者自动收货

4,其他类似需求...

类似这样的需求,我把它叫做延时任务,叫做定时任务不大合适,因为这类任务没有固定的触发时间,下面我们来分析总结下这类任务的解决方案:

a,定时轮询数据库

启动一个job(job调度与业务逻辑处理分离),定时扫描数据库,执行的操作类似select * from xxx where status='online' and created_at<=current_time-30分钟,获取到数据后,进行订单取消操作。

优点:简单,且可以支持集群扩展

缺点:(1)存在延迟,如果job一分钟执行一次,那么最大延迟就是1分钟

            (2)数据可能存在分布不均的情况,有可能超时的订单都集中在某个小范围时间段,其他时间段job相当于都在空跑

            (3)如果订单量巨大,每隔一分钟扫描一次,性能较差

该解决方案,我们实际中也有使用,定时任务大约5分钟跑一次,主要用于对时间要求不那么敏感且订单量较少(比如金融产品要求百万或者几百万的起投额,这样的业务单个订单的金额巨大,但是总体的订单量少)的场景。

b,jdk提供的延迟队列

jdk提供了一个现成的延迟队列实现,DelayQueue,DelayQueue<Element> queue = new DelayQueue<Element>(),这个Element必须要实现Delayed接口,当队列中的元素延迟到期后才能被取出来,可以通过在while循环中调用take方法获取到期的元素。

优点:所有的操作都在内存中,效率高,延迟非常低

缺点:(1)服务器如果重启后,数据就全部丢失了

        (2)如果订单量巨大,可能出现内存不够导致溢出,需要在初期充分预估内存大小

还有一种与这个类似的方法就是采用时间轮的方式,之前的文章中有介绍过,不过本质上也与方案b存在相同的问题。

c,jdk延迟队列或者时间轮+定时补偿任务

首先将订单信息(包含超时信息)写入到数据库,然后再写入必要的订单有关信息到jdk延迟队列中。jdk中的延迟任务处理后更新数据库中的订单信息。如果服务器重启数据丢失了,那么由补偿任务执行超时操作。

优点同b,缺点:还是可能出现内存不够导致溢出,需要在初期充分预估内存大小

d,redis缓存

根据方案b的缺点,害怕重启,以及内存溢出,那我们把这些数据都存到redis(规划专门的内存)中,这样也不怕机器重启和内存溢出了。可以利用redis提供的有序集合,具体可以看redisfans网站上的文档介绍。

首先我们使用zadd命令,其member为订单id,score为订单超时时间。然后在while循环中命令zrangebyScore查找超时时间小于等于当前时间的记录(System.currentTime),执行超时操作,然后删掉对应的member。

缺点:(1)redis需要进行额外的维护,redis还是有宕机的可能,宕机时主从切换的过程中可能丢失数据,需要解决这个问题(虽然可以通过配置保证数据不丢失,但会导致master拒绝客户端的写请求,另一种方法是也采用补偿的方式处理这种情况)。

        (2)如果同一时间超时的订单数巨大,zrangebyScore直接获取全部数据会有严重的性能问题,需要分页获取,这样会增大延迟,此时可能需要进行分片,

        (3)需要引入分布式锁避免单个订单被重复执行超时操作

e,使用消息队列延迟投递功能

比如利用rabbitmq的特性(TTL和dead letter exchanges),我们建议两个队列queue1和queue2首先将订单放入队列queue1,设置这个消息的时间为30分钟,超过时间后被转发到queue2,消息者消费queue2即可。

优点:高效,利于横向扩展,mq消息的持久化可以保证可靠性

缺点:需要引入rabbitmq,需要对其进行额外的维护(如果本身的项目中就用到了rabbitmq,那么可以采用这种方案)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值