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。

存入时间轮

// 时间轮的数据结构
private volatile static Map<Integer, List<Integer>> ringData = new ConcurrentHashMap<>();

// 存入时间轮
 private void pushTimeRing(int ringSecond, int jobId) {
        // push async ring
        List<Integer> ringItemData = ringData.get(ringSecond);
        if (ringItemData == null) {
            ringItemData = new ArrayList<Integer>();
            ringData.put(ringSecond, ringItemData);
        }
        ringItemData.add(jobId);

        logger.debug(
            ">>>>>>>>>>> xxl-job, schedule push time-ring : " + ringSecond + " = " + Arrays.asList(ringItemData));
    }

上面是处理存储的方法,接下来通过注释来表示,执行器怎么执行的

						//获取当前时间(ms)
					    long nowTime = System.currentTimeMillis();
					    // 获取未来5s内需要执行的任务
                        List<XxlJobInfo> scheduleList = XxlJobAdminConfig.getAdminConfig().getXxlJobInfoDao()
                            .scheduleJobQuery(nowTime + PRE_READ_MS, preReadCount);           
                        if (scheduleList != null && scheduleList.size() > 0) {
                            // 2、push time-ring
                            for (XxlJobInfo jobInfo : scheduleList) {

                                // time-ring jump
                                //如果当前时间>任务下次执行时间+5s(意思是任务已经超期,因为只执行5s内的任务)
                                if (nowTime > jobInfo.getTriggerNextTime() + PRE_READ_MS) {
                                    // 2.1、trigger-expire > 5s:pass && make next-trigger-time
                                    logger.warn(">>>>>>>>>>> xxl-job, schedule misfire, jobId = " + jobInfo.getId());

                                    // fresh next
                                    //刷新下次执行时间
                                    refreshNextValidTime(jobInfo, new Date());

                                } else if (nowTime > jobInfo.getTriggerNextTime()) {
                                //如果任务在5s内
                                    // 2.2、trigger-expire < 5s:direct-trigger && make next-trigger-time

                                    // 1、trigger
                                    //立马触发
                                    JobTriggerPoolHelper.trigger(jobInfo.getId(), TriggerTypeEnum.CRON, -1, null, null,
                                        null);
                                    logger.debug(
                                        ">>>>>>>>>>> xxl-job, schedule push trigger : jobId = " + jobInfo.getId());

                                    // 2、fresh next
                                    refreshNextValidTime(jobInfo, new Date());

                                    // next-trigger-time in 5s, pre-read again
                                    //	如果任务状态是启动的,且当前时间+5s>下次执行时间(该次为未来时间需要执行)
                                    if (jobInfo.getTriggerStatus() == 1
                                        && nowTime + PRE_READ_MS > jobInfo.getTriggerNextTime()) {

                                        // 1、make ring second
                                        //获取未来需要执行的秒数(如果执行时间为 2021/1/29 17:03:26  则返回26)
                                        int ringSecond = (int)((jobInfo.getTriggerNextTime() / 1000) % 60);

                                        // 2、push time ring
                                        //存入时间轮
                                        pushTimeRing(ringSecond, jobInfo.getId());

                                        // 3、fresh next
                                        refreshNextValidTime(jobInfo, new Date(jobInfo.getTriggerNextTime()));

                                    }

                                } else {
                                    // 2.3、trigger-pre-read:time-ring trigger && make next-trigger-time

                                    // 1、make ring second
                                    int ringSecond = (int)((jobInfo.getTriggerNextTime() / 1000) % 60);

                                    // 2、push time ring
                                    pushTimeRing(ringSecond, jobInfo.getId());

                                    // 3、fresh next
                                    refreshNextValidTime(jobInfo, new Date(jobInfo.getTriggerNextTime()));

                                }

                            }

                            // 3、update trigger info
                            for (XxlJobInfo jobInfo : scheduleList) {
                                XxlJobAdminConfig.getAdminConfig().getXxlJobInfoDao().scheduleUpdate(jobInfo);
                            }

                        } else {
                            preReadSuc = false;
                        }

接下来用时间轴来解释下执行器的执行条件
在这里插入图片描述

  • 条件1 nowTime > jobInfo.getTriggerNextTime() + PRE_READ_MS
  • 条件2 nowTime > jobInfo.getTriggerNextTime()
  • 条件3 jobInfo.getTriggerStatus() == 1 && nowTime + PRE_READ_MS > jobInfo.getTriggerNextTime()
  • other

通过如上条件完成对小于5s内的所有任务的处理·

总结

通过阅读源码发现在临界情况(极端量级)下存在任务漏调度或者不调度的情况,不知道其他调度器是否存在,如有错误敬请斧正

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
XXL-Job执行器XXL-Job分布式任务调度平台中的一个核心组件,负责接收和执行调度中心发送的任务。执行器可以独立部署在各个执行节点上,通过与调度中心进行通信,实现任务的调度和执行。 XXL-Job执行器提供了丰富的功能和接口,主要包括以下几个方面: 1. 任务执行:执行器接收到调度中心发送的任务后,负责根据任务类型进行相应的执行。XXL-Job支持多种任务类型,如Shell任务、Java任务、Python任务等,执行器会根据任务类型来执行相应的逻辑。 2. 任务参数传递:执行器可以接收调度中心传递的任务参数,并将参数传递给具体的任务执行逻辑。任务参数可以在任务配置中进行设置,执行器会根据配置将参数传递给任务。 3. 任务结果回调:执行器在任务执行完成后,会将任务执行结果回调给调度中心。调度中心可以根据任务执行结果进行相应的处理,如记录日志、发送通知等。 4. 心跳检测:执行器会定期向调度中心发送心跳信息,用于告知调度中心自身的存活状态和可用性。调度中心可以通过心跳检测来监控执行器的健康状态。 5. 日志上报:执行器会将任务执行过程中的日志上报给调度中心,便于开发者查看任务的日志输出和排查问题。 XXL-Job执行器可以根据实际需求进行灵活的部署和配置,可以实现任务的并发执行和负载均衡,提高任务执行的效率和可靠性。同时,执行器还提供了可扩展的接口,可以与其他系统进行集成,满足更复杂的业务需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值