这是我参与「第三届青训营 -后端场」笔记创作活动的第3篇笔记
分布式定时任务的实现原理
主要由三部分组成:
- 触发器:Trigger, 解析任务,在规定时间触发要执行的任务
- 调度器:Scheduler, 按一定规则将任务交给执行器执行任务
- 执行器:Executor, 执行任务
Trigger
方案一:定期扫描+延时消息
方案二:时间轮算法
这也是Quartz所使用的方案,主要是通过循环数组加链表实现
循环数组的每个索引位代表不同时间段,并且每个索引位都是一个任务链表,表示在该时间需要执行的所有任务
时间轮算法的优点在于其查询和修改的复杂度都是O(1)。
在实际应用场景中,通常都是使用多级时间轮来存储任务的:
例如,任务2规定是在2时3分1秒时刻执行:
那么任务首先会在时轮2位置,当时轮转到2时,就会将任务转移到分轮3的位置,当分轮转到3时,又会将任务转移到秒轮,当秒轮转到1时便触发改任务的执行。
当然,当任务时间跨度大时,也可以引入天轮,月轮,年轮。
以上的描述似乎都与分布式没啥关系,分布式和单机到底有啥区别?
单机定时任务:比如一个大型项目通过五台服务器进行负载均衡,每台服务器都有业务代码和定时任务代码,并且定时任务都是通过各自的线程池定时执行的,那么同一个任务就会被执行五次,造成资源的浪费,甚至会出现数据紊乱。
容易想到的是将其余的四个服务器定时任务都删掉,只留一个来执行,这样貌似就可以解决了。但是这种单点模式发生故障的概率是很高的。
分布式定时任务调度横空出世:
任务都存放在DB中,每个触发器到触发事件时都会对数据库进行锁竞争,这样可以保证,每个任务都只被执行一次,并且,多Trigger模式出现故障的概率降低