定时调度任务解决方案

#概述

我们在业务开发中经常会遇到类似的需求: 10分钟未付款的订单需要自动取消掉,30分钟没有活动的用户需要注销掉等。通常的解决方法有以下两种:

轮询处理

1,构建一个集合。

2,新的订单过来时,放入该集合。

3,启动一个定时器,每分钟扫描一次该集合处理符合条件的订单。

多定时器回调

1,新的订单过来时,设置一个10分钟的定时器。

2,定时器触发时,处理该订单是否要取消。

方案一:只启动一个定时器,但是需要扫描整个集合。依赖于集合的大小,如果集合过大,则业务处理延时非常大。并且每次都要扫描整个集合,造成很多重复的运算检查。效率非常低下。

方案二:需要启动多个定时器,当任务量过大的时候,会把内存撑爆。

#环形任务槽处理

通过建立多个任务槽,每个槽只存储一部分订单id。启动一个线程,处理当前时间需要处理的槽的数据。新的订单过来时,放入当前时间对应槽的前一个。

1,我们定义10个槽。同时启动一个定时器,每分钟执行一次。

2,定时器执行时,(取当前时间分钟数)%10,得到要处理的槽,比如槽0。则处理槽0里面所有的订单,检查是否超时。

3,新的订单过来时,(取当前时间分钟数-1)%10,得到对应的槽,比如槽9,将订单id放入槽9。则10分钟后,就会处理到槽9.

实现代码如下:

测试代码如下:

在实际编程中我们需要注意,如果当前任务周期内没有把所有的任务都处理完的处理方案的选择。继续当前任务周期内任务处理就会占用下个任务周期的时间,或者未处理完的任务在下个周期再进行处理。

优点:只需要启用一个定时器,并且不需要轮询所有的订单id。

缺点:如果要执行的任务周期比较长时,并且任务时间窗口比较小时,则需要开启很多的槽。

扩展

以上只是一个demo的实现,在实际业务中我们可能需要考虑使用kafka消息队列来做实现。每个topic代表一个任务槽,kafka消息队列天然具有分布式任务处理能力,当任务量很大时可以通过增加消费者的方式获取待处理任务。另外,任务的具体执行可以通过线程池或分布式任务任务调度程序执行,快速的在指定时间周期内,处理完任务。

任务周期比较长时,槽的数量会非常短,同时也使每个槽内的任务数比较少。这种情况,可以使用redis的队列处理。

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180322A0ZET100?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券