xxl-job 调度中心如何进行进行任务调度

简介

再看一遍 xxl-job 架构图:
在这里插入图片描述
调度中心主要提供了两个功能: 系统管理 和 任务调度。其余的都是一些辅助功能。

  • 系统管理正如图中所示的那样, 包括任务管理、执行器管理、日志管理。还提供了管理界面。
  • 任务调度就是负责从数据中心拉取任务,并按照执行时间将任务投递给执行器。

调度器的组成结构

在这里插入图片描述

两个核心线程

当调度中心启动后,会启动以下两个线程:

  1. schedulerThread
    scheudlerThread主要做如下两件事情:
  • 从数据中心(db),也就是 xxl_job_info表中扫描出符合 条件 1 的任务, 条件1 限制如下:
    • 任务执行时间 小于(当前时间 + 5 s)
    • 限制扫描个数, 这个值是动态的,会根据后面的提到的 快慢线程池 中线程数量有关系。
    count = treadpool-size * trigger-qps  (each trigger cost 50ms, qps = 1000/50 = 20) 
    
    treadpool-size = (getTriggerPoolFastMax() + getTriggerPoolSlowMax()) * 20
    // 看完快慢线程池的介绍,再回过头来看这里,会更容易理解  
  • 扫描出来的任务被划分为以下 3 类:
  • 在这里插入图片描述
  1. ringThread

ringThread的作用就是不断从 容器 中读取 当前时间点需要执行 的任务, 读取出来的任务会交给一个叫 快慢线程池 的东西去将任务传递给调度器去执行。

时间轮

上述的 ringThread和 容器 共同组成了一个时间轮。

简单来讲,时间轮实现了 延迟执行 的功能,它在 xxl-job 中的作用就是让 还未到达执行时间 的任务,按照预计的时间通过 快慢线程池 一个一个送到 执行器 中去执行。

  • 时间轮的数据结构一般是 数组 + 链表, 和 jdk1.7 中的 HashMap 是一个道理,链表中的每个节点就是一个待执行的任务。

  • xxl-job 中的时间轮可以形象描述为以下这张图,像一个只有秒针的钟表一样。

  • ringThread 线程运行过程中,每秒会扫过一个刻度,假设当前刻度位置存在 job 链表,就把链表中的所有 job 取出来,最后丢给 快慢线程池。

  • 当然 xxl-job 为了避免处理耗时太长,会跨过刻度,多向前校验一个刻度;也就是当指针指到 2s 时,会把 1s 和 2s 位置的任务同时读取出来。
    在这里插入图片描述

快慢线程池

上面提到任务从数据中心扫描出来后,随之就会被丢到快慢线程池中,快慢线程池的定义如下:

fastTriggerPool = new ThreadPoolExecutor(
                10,
                XxlJobAdminConfig.getAdminConfig().getTriggerPoolFastMax(),
                60L,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>(1000),
                new ThreadFactory() {
                    @Override
                    public Thread newThread(Runnable r) {
                        return new Thread(r, "xxl-job, admin JobTriggerPoolHelper-fastTriggerPool-" + r.hashCode());
                    }
                });

        slowTriggerPool = new ThreadPoolExecutor(
                10,
                XxlJobAdminConfig.getAdminConfig().getTriggerPoolSlowMax(),
                60L,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>(2000),
                new ThreadFactory() {
                    @Override
                    public Thread newThread(Runnable r) {
                        return new Thread(r, "xxl-job, admin JobTriggerPoolHelper-slowTriggerPool-" + r.hashCode());
                    }
                });

由上可知, 快慢线程池包含了两个线程池 fast 和 slow,当一个 job 提交到快慢线程池后,快慢线程池会根据一些条件, 选择其中一个线程池去执行后续的操作。

快慢线程池的作用如下:

实现线程池隔离:调度线程池进行隔离拆分,慢任务自动降级进入”Slow”线程池,避免耗尽调度线程,提高系统稳定性;

什么是慢任务?

如果一个任务在 1 分钟内,它的执行超时次数超过 10 次,就被归为 慢任务

当具体的快或者慢线程池接收到调度任务时,会通过 RPC 远程调用去触发 执行器 完成任务的执行逻辑。

源码入口

com.xxl.job.admin.core.thread.JobScheduleHelper#start

com.xxl.job.admin.core.thread.JobTriggerPoolHelper#addTrigger

com.xxl.job.core.biz.client.ExecutorBizClient#run

总结

本文基于 xxl-job v2.x 的源码分析了 xxl-job 调度器的组成结构 以及 调度中心是如何触发任务的。

调度器主要包含了以下模块:

  • schedulerThread: 负责从数据中心扫描需要执行的任务
  • ringThread: 负责精准地控制预计需要执行的任务
  • 快慢线程池:通过包装两个线程池,去分别执行 快任务 和 慢任务 的调度过程。

时间轮附录

https://www.cnblogs.com/yuarvin/p/14445613.html

posted on 2021-02-25 10:37  书梦一生  阅读(2753)  评论(4编辑  收藏  举报

导航