xxl-job 调度中心的演进过程
一开始程序是单机的,定时任务只部署在一个机器上,但是这个时候就存在单点故障了,
如果这台机器宕机了,那么定时任务就无法执行了。
怎么办呢?
部署集群呗,定时任务部署在两台机器上。
当其中一台机器发生故障的时候,只要另一台机器正常运行,那么定时任务还是可以正常执行的。
集群部署之后,但是存在一些问题:
1、定时任务的逻辑是幂等的嘛?如果只是去查询数据库做一些统计的工作,那么执行一次,两次的影响是一样的,没有关系。但是,如果是更新,插入等操作呢,就有可能存在并发安全问题,从而导致数据错乱。
所以需要通过分布式锁,来保证定时任务只被执行一次。
2、每个定时任务都是依赖当前机器的时间,但是不同机器之间的时间可能存在偏差的,这个问题解决起来就很麻烦,能不能共同依赖一个公共的时间表尺呢?
如果没有调度中心,那么代码会存在什么问题呢?
1、调度任务的逻辑会和定时任务本身的逻辑,耦合起来,写定时任务的时候会很烦,还要考虑调度的逻辑,
但是这样是不方便开发的,所以就需要把调度任务的逻辑和定时任务本身的逻辑,解耦开来。
这个时候就需要抽象出来一个调度中心了。
2、上面说的不同机器之间的时间是存在偏差的,处理起来是很麻烦的。但是有了调度中心之后,调度的逻辑,就变为调度中心去查询数据库,数据库中记录了定时任务的下一次执行时间,然后通过网络去通知让某个定时任务去执行。定时任务执行时间的判断依据的是调度中心部署服务器的时间,而不是两个定时任务部署的服务器,这样,执行时间就终于有了一个统一的标尺。
现在整体的架构图是这样的:
1、定时任务部署在两台机器上
2、调度中心单独部署在一台机器上
讲一下整体的逻辑:
1、定时任务部署的机器,我们称为执行器端,执行器端系统启动的时候,需要把机器的 ip 端口号信息注册到调度中心,为什么不要注册定时任务的信息呢?
这是因为定时任务,是用户在 web 页面上手动注册的,注册的时候,会绑定一个执行器。
2、调度中心,这边查询数据库,查到需要执行的定时任务,就通过某个路由策略,选择出具体的一个机器,然后通过网络通知执行器端来执行对应的某一个定时任务。
当然 xxl-job 代码中,并没有说的这么简单,其中还是有很多亮点的设计:
● 为了确保在调度中心的高可用 HA 集群部署下,任务不会被重复调度,使用 MySQL 实现了分布式锁
● 任务调度流程全异步化设计实现,如异步调度、异步运行、异步回调等,有效对密集调度进行流量削峰
● 在任务触发组件中引入快慢线程池,避免线程池资源被耗时较长的任务耗尽,导致耗时较短的任务无法被触发执行
● 采用预读机制结合时间轮算法,并且分类讨论任务调度的各种情况,保证任务调度的精度和降低数据库的压力
大家可以去看一下源码,学习一下设计,xxl-job 的源码也并不困难,花费几天的时间应该就可以读个大概了。
读者阅读过源码之后,感觉受益匪浅。
其中的很多设计,其实在业务代码中也是可以借鉴使用的。