来源:juejin.cn/post/6844903954145361927
推荐:https://t.zsxq.com/kC5TA
前言
废话少说,直接进入正题。
相信大家对XXL-JOB都很了解,故本文对源码不进行过多介绍,侧重的是看源码过程中想到的几个知识点,不一定都对,请大神们批评指正。
XXL-JOB简介
-
XXL-JOB是一个轻量级分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。 -
XXL-JOB分为调度中心、执行器、数据中心,调度中心负责任务管理及调度、执行器管理、日志管理等,执行器负责任务执行及执行结果回调。
任务调度 - “类时间轮”的实现
时间轮
时间轮出自Netty中的HashedWheelTimer,是一个环形结构,可以用时钟来类比,钟面上有很多bucket,每一个bucket上可以存放多个任务,使用一个List保存该时刻到期的所有任务,同时一个指针随着时间流逝一格一格转动,并执行对应bucket上所有到期的任务。任务通过取模决定应该放入哪个bucket。和HashMap的原理类似,newTask对应put,使用List来解决 Hash 冲突。

以上图为例,假设一个bucket是1秒,则指针转动一轮表示的时间段为8s,假设当前指针指向 0,此时需要调度一个3s后执行的任务,显然应该加入到(0+3=3)的方格中,指针再走3s次就可以执行了;如果任务要在10s后执行,应该等指针走完一轮零2格再执行,因此应放入2,同时将round(1)保存到任务中。检查到期任务时只执行round为0的,bucket上其他任务的round减1。
当然,还有优化的“分层时间轮”的实现,请参考https://cnkirito.moe/timer/。
XXL-JOB中的“时间轮”
-
XXL-JOB中的调度方式从
Quartz变成了自研调度的方式,很像时间轮,可以理解为有60个bucket且每个bucket为1秒,但是没有了round的概念。 -
具体可以看下图。

-
XXL-JOB中负责任务调度的有两个线程,分别为 ringThread和scheduleThread,其作用如下。
❝
1、scheduleThread:对任务信息进行读取,预读未来5s即将触发的任务,放入时间轮。2、ringThread:对当前
bucket和前一个bucket中的任务取出并执行。
-
下面结合源代码看下,为什么说是“类时间轮”,关键代码附上了注解,请大家留意观看。
@JobHandler(value="shardingJobHandler")@ServicepublicclassShardingJobHandlerextendsIJobHandler{@OverridepublicReturnT<String>execute(Stringparam)throwsException{//分片参数ShardingUtil.ShardingVOshardingVO=ShardingUtil.getShardingVo();XxlJobLogger.log("分片参数:当前分片序号={}, 总分片数={}",shardingVO.getIndex(),shardingVO.getTotal());//业务逻辑for(inti=0;i<shardingVO.getTotal();i++){if(i==shardingVO.getIndex()){XxlJobLogger.log("第{}片,命中分片开始处理",i);}else{XxlJobLogger.log("第{}片,忽略",i);}}returnSUCCESS;}}
-
由此得出,分布式实现是根据分片参数 index及total来做的,简单来讲,就是给出了当前执行器的标识,根据这个标识将任务的数据或者逻辑进行区分,即可实现分布式运行。 -
题外话:至于为什么用外部注入分片参数的方式,不直接 execute传递?
❝
1、可能是因为只有分片任务才用到这两个参数
2、IJobHandler只有String类型参数
看完源码后的思考
本篇文章来源于微信公众号: 业余草
微信扫描下方的二维码阅读本文

Comments NOTHING