分布式定时任务-任务调度

1,654 阅读3分钟

1 漫谈任务调度

1.1 什么时候需要任务调度?

1.1.1 任务调度的背景

在业务系统中有很多这样的场景:

1、账单日或者还款日上午 10 点,给每个信用卡客户发送账单通知,还款通知。如 何判断客户的账单日、还款日,完成通知的发送?

2、银行业务系统,夜间要完成跑批的一系列流程,清理数据,下载文件,解析文件, 对账清算、切换结算日期等等。如何触发一系列流程的执行?

3、金融机构跟人民银行二代支付系统对接,人民银行要求低于 5W 的金额(小额支付)半个小时打一次包发送,以缓解并发压力。所以,银行的跨行转账分成了多个流程: 录入、复核、发送。如何把半个小时以内的所有数据一次性发送?

类似于这种 1、基于准确的时刻或者固定的时间间隔触发的任务,或者 2、有批量数据需要处理,或者 3、要实现两个动作解耦的场景,我们都可以用任务调度来实现。

1.2 任务调度需求分析

任务调度的实现方式有很多,如果要实现我们的调度需求,我们对这个工具有什么样的基本要求呢?

1.2.1 基本需求

1)可以定义触发的规则,比如基于时刻、时间间隔、表达式。

2)可以定义需要执行的任务。比如执行一个脚本或者一段代码。任务和规则是分开的。

3)集中管理配置,持久配置。不用把规则写在代码里面,可以看到所有的任务配置,方便维护。重启之后任务可以再次调度——配置文件或者配置中心。

4)支持任务的串行执行,例如执行 A 任务后再执行 B 任务再执行 C 任务。

5)支持多个任务并发执行,互不干扰(例如 ScheduledThreadPoolExecutor)。

6)有自己的调度器,可以启动、中断、停止任务。

7)容易集成到 Spring。

1.3 任务调度工具对比

层次举例特点
操作系统Linux crontab <br>Windows 计划任务只能执行简单脚本或者命令
数据库MySQL、Oracle可以操作数据。不能执行 Java 代码
工具Kettle可以操作数据,执行脚本。没有集中配置
开发语言JDK Timer、ScheduledThreadPoolTimer:单线程<br>JDK1.5 之后:ScheduledThreadPool(Cache、Fiexed、Single):没有集中配置,日程管理不够灵活
容器Spring Task、@Scheduled不支持集群
分布式框架XXL-JOB,Elastic-Job

@Scheduled 也是用 JUC 的 ScheduledExecutorService 实现的Scheduled(cron = “0 15 10 15 * ?”)

1、 ScheduledAnnotationBeanPostProcessor 的 postProcessAfterInitialization 方法将@Scheduled 的方法包装为指定的 task添加到 ScheduledTaskRegistrar 中

2、 ScheduledAnnotationBeanPostProcessor 会监听 Spring 的容器初始化事件,在 Spring 容器初始化完成后进行TaskScheduler 实现类实例的查找,若发现有 SchedulingConfigurer 的实现类实例,则跳过 3

3、 查找 TaskScheduler 的实现类实例默认是通过类型查找,若有多个实现则会查找名字为"taskScheduler"的实现 Bean,若没有找到则在 ScheduledTaskRegistrar 调度任务的时候会创建一个 newSingleThreadScheduledExecutor,将TaskScheduler 的实现类实例设置到 ScheduledTaskRegistrar 属性中

4、 ScheduledTaskRegistrar 的 scheduleTasks 方法触发任务调度

5、 真正调度任务的类是 TaskScheduler 实现类中的 ScheduledExecutorService,由 J.U.C 提供

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第32天,点击查看活动详情