00:00
好,那我们接下来的话呢,我们就开始写这个定时调度模块,对吧,或者说任务调度模块,呃,也就是我们这里的,诶这里边的这个任务调度模块,当然现在我们还没有写它的API以及一些功能,呃,当然说就是说在讲这个任务调度模块以前呢,呃,我们首先要明白,就是说在业界的任务调度框架,那么他一般来说会做什么样的事情呢?它一般来说,呃,他会调度两种类型的任务,那么第一种类型呢,叫做定时任务。对吧?呃,什么叫做定时任务呢?那么定时任务的话呢,那就是呃比方说我设置一个周期对吧,每隔十秒钟执行一次这个任务,那这个叫做一个定时任务,呃,当然除了这个以外呢,那还有一个呢,就是我们比较有名的这样的一个C这样的一个任务,对吧?呃,其实C任务呢,它当然也是一个定时任务,对吧?呃,如果说呃大家有学过这个Linux系统的话呢,那应该知道crown任务或者说crown tab它本身是一个干什么的,对吧?所以我们在这的话呢,你比方你可以呃搜一下。
01:13
Crown表达式对吧?呃,大家可以先来了解一下这个crown tab,就是说在我们的呃Linux里面,你是如何编写这个框表达式呢?来让它呃做一个定时任务这样的东西对吧?呃,我们可以简单的看一些这样的一个表达式,呃,那在这里边的话呢,我就随便打开一个网页对吧?呃,那你在这的话你就会发现。呃。这样的一个表达式的话,你会发现,哎,秒是什么呢?秒是呃允许的是零到59,然后分呢,是零到59对吧,小时是零到23对吧?那么这个就是一个c tab的呃,Crown,呃表达式的一个语法对吧?当然我们可以看一些例子对吧?我们可以看一下例子,呃,OK,那么在这的话呢。
02:03
我们打开一个对吧,随便来看一个例子,比如说你在这里边你写了这样的一个表达式对吧?比如说如果我们想要指定2022年每天上午08:15执行一个任务的话呢,那么你C的表达是可以这么来写,零十五八。问号,然后两个通配对吧,两个星号,然后2022对吧,或者说零十五零八问号两个通配两个星号2022,也就是说这样的一个表达式C表达式,呃,如果你在Linux系统对吧,你写一个c tab这样的一个任务的话呢,呃,那么它就会。在呃就是说每天的08:15呢,来执行一个任务对吧,每天的呃,这个08:15呢,来执行一个任务,所以说这个crown任务呢,它本身也是一种什么呢?呃也是一种定时任务对吧?也是一种定时任务啊,那你可以看到哎这个c tab啊,这个呢,就是在我们的Linux里边呢,你就可以去呃写配置文件对吧?然后呃就是说执行定时任务对吧?比方这个crown呢,本身是Linux下面一个定时执行工具,也就是我们在无需人工干预的情况下的定时执行任务,对吧?比如说这里边有一个service crowd start,什么service crowd stop,对吧,关闭服务crowd start呢是重启服务,那么c tab。
03:33
它的保存路径呢,是vapo crown,然后crown types在这个文件里面对吧,在这个文件里面,然后你在这个文件里面呢,你就可以写这个呃框表达式了,对吧?以及你要执行的任务对不对,你可以看到诶这里边当然它这个高亮可能并不是那么亮,对吧?这里边前面几个是星号。对吧。然后呢,有一个command,那这个就是每分钟执行一次command,对吧?那你如果说是每个小时的第三和第20分钟执行一次,呃,这个command,当然你要注意这个command呢,它是一个shell命令,那就是三逗号20,然后六个星号command对吧?呃,当然你可以在这里面呢,呃,把它写到这儿可能好看一点,三逗号20,然后四个星号,然后shell命令对吧?那么它就是每呃就是说那么它执行的方式是什么呢?那么它执行的方式就是每小时的第三分钟和第20分钟对吧?每小时的第三分钟和第20分钟呢,来执行一次,呃,这个上网命令,那这个就是呃,Linux里边crow tab或者说表达式,它的一个用法,对吧。
04:47
也就是说,说白了就是说我们这个C任务呢,它本身也是一个,呃,就是说定时执行的任务,对吧,只不过它和周期的呃定时执行任务不太一样,对吧?比方说我们说周期性的执行的话呢,它是一个,比如说是每隔十秒钟执行一次啊,或者每隔一个小时执行一次,对吧?啊,那这个它就不是一个C任务,它是一个周期性的呃定时执行任务,而C任务呢,它主要指定的是一些比较复杂的一些任务,比方说。
05:17
对吧,你每天的08:15要执行一个任务,对不对,等等等等,那你可以看到这边015呢,就是15分,那八就是八点的意思,对吧?啊,那后面的话呢,我们就不需要管它了,那么这个2022呢,就是2022年执行它对吧?那这个就是口号表达式,那么它会比呃我们的周期执行的这样的定时执行任务呢?呃,它定时的方式会更加复杂,但是它本质呢,呃,还是一个定时执行任务,对吧?呃,所以说我们。一般来说业界它的任务调度框架,或者是任务调度工具的话呢,它第一种呃,要调度的呢,就是定时任务对吧,那么定时任务呢,又分两种对吧,第一种是呃CN任务,那第二种的话呢,是。
06:07
对吧?周期执行的任务对吧?周期执行的任务那一般就是这两种,那除了定时任务以外呢?呃,那么我们比方说像dolphin schedule了,对吧,它实际上就可以呃去调度这个定时任务对吧,Dolphin schedule了,呃,那么除了定时任务以外,这是第一大类呢?第二大类是什么呢?第二大类就叫做这个dag这样的一个任务,Dag任务的调度对吧?那么dag任务调度什么意思呢?首先我们要明白,Dag表示的是它的意思是有向无环图,那么dag任务它的调度逻辑是什么呢?那么他的调度逻辑或者说他要干什么样的事情呢?比如说我们这里面有这么几个任务,呃,第一个呢,是任务一,对吧。呃,那第二个的话呢,比如说是一个任务二,那么我们想要完成一个什么样的功能呢?比如说我想要任务一执行完以后再执行任务二,对吧?呃,然后呢,当然就是说我们把这个往上调节一下啊,把它放这儿吧,啊比如说在这里边的话呢,我想要保证就是说任务一执行完以后执行任务二,那么任务二执行完以后执行任务三,呃,当然它执行顺序是这样子的。
07:34
好。啊,当然这个有效无环图的话呢,它还可以更复杂,比方说我,呃任务一执行,比方说我这个任务二执行完以后,呃,除了执行任务三以外,还有可能执行任务四,对吧,这也是有可能的,对吧?好。啊,那我们可以看到这个就是一个有向无环图。那么它调度的难点在于哪里呢?或者说它调度的关键点在于哪里呢?就是我们一般来说会把这个有效无环图呢,写成一个配置文件,然后提交以后呢。
08:08
呃,调度器呢,就会自动去调度这样的一个工作流,对吧,自动去调度这样的一个工作流,那么它就会保证什么呢?它就会保证你任务一执行完再执行任务二,那么任务二执行完再去执行任务三或者任务四对吧,任务三或者任务四。啊,它是这样的一种调度逻辑,也就是它跟时间就没有关系啊,它要保证的是我们这个有向无环图里边,对吧,你任务一一定要在任务二执行完之前,就是说一定任务一一定要执行完之后才能执行任务二对吧,那么任务三和任务四执行完之前呢,一定要先执行完任务二对吧,那这个就是呃DA这任务的一个调度,呃,那他经常用的比方说数据处理对吧,就是说你呃这个数据处理呢,可能有很多个任务,他必须是一个任务。
09:05
对吧,执行完以后,处理完输出的数据,输出给第二个任务,然后第二个任务才能开始执行,对吧?它是有前后的严格的依赖关系的,呃这样的一个呃就是说工作流,那么这个就适合用呃dag任务的调度器来进行调度,对吧?也就是说实际上它必须按照呃这个任务的拓扑排序来进行调度,什么叫做拓扑排序呢?那就是说因为它是个有向无环图嘛,那就是呃我的。一条边的对吧圆顶点,比方说这条边的圆顶点,任务一必须在对吧任务二之前开始之前就执行完,对吧,那这个就是呃,按照任务的拓扑排序来进行调度,对吧?那么它的代表框架是什么呢?那么它的代表框架呢,就是呃,Air flow对吧,Air flow当然就是像呃,Dolphin schedule,对吧,他也能做这样的一个事情,呃因为一个成熟的调度框架来讲的话呢,呃就是说它既可以完成定时任务的调度,也可以完成有向无环图dag任务的调度,对吧,一般来说一个成熟的呃就是说任务调度框架,呃它都具备这两个功能,呃,当然就是说。
10:26
呃,包括可能还有类似于像阿兹卡班这样的工具,对吧?呃,当然就是你清楚了他是在做什么事情,实际上你就可以任选一个工具,对吧?把它用熟就可以了,好,那这个是它调度任务的类型,那除了调度任务的类型以外呢,它还需要拥有什么样的功能呢?那就是分布式调度对吧?呃,什么叫做分布式调度呢?就是我一个任务,我希望把它。对不对,同时呢,在好多个节点,或者说好多台机器上呢,去呃,让它执行对吧,这个就是分布式的调度,也就是说。
11:04
我要定时在多台机器上执行某一个任务,对吧?这个叫做呃,分布式的调度呢,这个也是我们调度框架,它通常所具备的一个功能,对吧,通常所具备的功能,呃,当然我们这里边的话呢,我们并不会选择说是呃,直接使用dolphin schedule或者说air flow,对吧?呃,因为这个dolphin schedule实际上是已经别人开发好的,而我们这里边的话呢,我们要使用的是Java里边一个非常有名的定时人物调度库,可以说是最有名的,叫做呃,Quas这样的一个,呃。啊,当然跨S它是石英的意思对吧,或者说是呃这个石英晶体的意思,那么这个quas呢,是Java里边,呃可以说最有名的一个定时人物,呃调度的框架或者说库,或者说工具对吧?呃,那比方说dolphin schedule呢,实际上它就是基于跨次来进行实现的,呃所以说我们这里边的话呢,我们要呃基于跨次呢,来自己实现一个呃这个定时任务调度器,对吧?当然实现的呢比较简单,呃如果说呃我们想在中台里边对吧,你实现想要实现非常复杂的任务调度工具的话呢,呃,你也可以给予我们的教程呢,继续拓展,当然呃可能没有那么大的必要,对吧?为什么这么说呢?因为。
12:30
你直接使用业界成熟的。都分schedule对吧?海豚调度器或者说air flow lbnb开源的对吧?你直接用第三方的这个成熟的工具就可以了啊,当这两个工具都满足不了你的需求的时候呢,那我们再选择使用更加底层的库来,呃,就是说实现这个功能对吧?来实现这个功能好OK,那我们接下来的话呢,我们就来对这个跨次呢来进行一个简单的讲解,呃,当然就是说除了跨子以外呢,呃,我们最常用的对吧?呃,当然就是说Java标准库里面的定时器,那么Java标准库里面定时器其实它也可以用来做定时任务的调度,那么我们为什么不使用Java timer呢?呃,这主要是因为,呃,你使用Java timer的话呢,它实现的功能可能相对来说比较有限,呃,它有限在哪里呢?比方说我这个定时器,对吧,我设置了一个。
13:33
下周一要执行的一个任务,对吧,这个Java的timer,这个定时器它是可以实现的,对不对,但是有什么样的一个问题呢?我设置了一个下周,比方我跑一个Java程序,然后呃,我设置一个下周一的这样的一个定时任务,对吧?或者定时器,那你这个Java任务在下周一之前你就宕机了,对吧。就报错了,然后那你自然下周一的这个定时事件你就没有办法执行了,换句话说什么呢,也就是说Java timer呢,它没有什么功能的,它没有办法把这个定时器保存下来,它是没有呃,这个定时任务的持久化功能的。
14:14
对吧,当然对于跨来讲的话呢,它就可以进行对吧,定时任务的持久化,也就是说。你每注册一个定时任务,或者说每调度一个定时任务呢,你都可以选择把它保存在比方说MYSQL里面。对吧,那你保存在MYSQL里边,这样我就不怕我的Java程序宕机对吧?因为我宕机以后,我这个程序重启了,我还可以从数据库里边把这个定时任务对吧,原先已经呃设置好的这个定时任务呢,再给它读取回来,对吧,就不需要你重新去呃注册定时器的对吧,或者说注册定时任务,它实际上是有有这样的一个好处,主要就是这个好处就是呃这个定时任务的持久化对吧,定时任务的持久化,你可以选择把它呃持久化在买SQL里边,对吧?呃当然它默认的话呢,它的定时任务都是保存在呃内存里边的。
15:14
都是保存在内存里边的,当然你要想让它持久化的话呢,本身也也不太难,就是写一个呃配置文件的事情,对吧?写一个配置文件的事情好,那接下来的话呢,呃,我们就来写一个小例子,对吧?来看一下这个跨词它主要是怎么使用的,呃,当然的话呢,就是说这个依赖的话呢,我们就已经导进来了,对吧,也就是这个2.quas-schedule,然后artifact的ID弓箭ID呢是quas,然后版本号是2.3.2,呃是当前最新的一个版本对吧?是当前最新的一个版本,呃,那么接下来的话呢,诶,我们专门开一个模块,那么这个模块叫什么呢?啊,那这个模块就叫做呃。
16:00
跨tutorial吧。对吧,呃,它里边也没有服务,也没有控制器,只是用来呃就是说我们要做一个呃跨这个工具的一个教程,对吧?小例子我们来看一下怎么用,其实它本身来说的话呢,是呃是非常简单的对吧,是非常简单的好那在这儿的话呢,我首先。我新建一个Java类,那么这个Java类叫什么呢?这个Java类叫simple job吧,呃,也就是说它是一个简单任务类,对吧,它是个简单任务,那这是一个。好,非常简,呃,简单的任务对吧?呃,它是个非常简单的任务啊,当然这个简单的任务的话呢,我们来看一下做了什么事情,它非常的简单呢?就是直接打印一个说诶,任务已经执行了,好,那在这里边我们如何把它变成一个跨次可以识别的任务呢?那这里边的话呢,你需要实现一个job这样的一个,呃,就是说接口对吧,实现job这样的一个接口,当然在这的话呢,我需要给他一个空构造器吧,呃,这样会比较保险一点,好,然后接下来的话呢,我们override一个execute这样的一个,呃。
17:22
函数对吧,那么这个execute我为什么要去重写它呢?因为这个execute就是说当你想要调度这个simple job这样的一个定时任务的时候呢。对吧,那么你第二,那么到了时间,哎,这个simple job,如果他想要执行它执行的代码逻辑是什么呢?那其实就是下面这个execute对吧?那这个是定时任务的业务逻辑对吧?当然我们在这儿的话呢,我们的业务逻辑非常简单的,就是打印一行叫做什么任务。
18:00
被触发执行对吧?任务被触发执行好啊,那这样的话呢,我们这个简单的任务呢,就已经写好了,我们就已经写好了啊,那么写好以后呢,我们接下来我们要做什么样的事情呢?我们接下来就要使用一下这个跨S呢,来进行一个调度,对吧?来进行一个调度好啊,我们在这儿的话呢,诶我们接下来的话呢,我们就在这写一个。Java类这个扎va类叫做什么呢?这个扎va类叫做呃,Test qua吧,对吧,Test qua也扎了好然后呢,我们在这儿的话呢,我们来看一下我们来如何写对吧,首先第一个获取调度器工厂类对吧?获取调度器工厂类那么万。Sky factory等于什么呢?等于new一个std。
19:02
然后呢?Schedule factory,那这个就是我们的一个,呃,就是说工厂类对吧,这个就是一个工厂类,当然在这的话呢,呃,我其实应该是写一个main函数对吧?因为你可以看它这个并不能识别,因为这个Y这样的一个关键字,它必须是初始化这个,呃局部变量的时候,它可以用外这个关键字,好啊,那么接下来的话呢,我现在有了,呃调度器的工获取调度器的工类我已经获取了,对吧,然后我使用工厂类呢,实例化一个调度器,对吧。实例画一个调度器,呃,一般来讲的话呢,我们一个呃,Spring boot的后端服务,可能你全局只需要一个调度器就可以了,所以说你可以把它呃实现成单立模式,对吧,我们后面我们也会选择呃把它实现成单立模式,好那么在这的话呢,V。Schedule对吧?K等于什么呢?K fact.get scheduled,那这样的话呢,就实例化的一个调度器啊,对吧?当然在这的话呢,实际上这个你实例化调度器的时候呢,呃,它是需要抛出异常的,对吧?所以我们直接来main函数抛出异常,方便我们测试,然后呢,启动调度器对吧?调度器的启动怎么进行启动呢?非常简单的就是schedule start对吧?呃,当然我们现在虽然启动了调度器呢,但是我们并没有调度任何的任务,所以说我们在这儿的话呢,我们就诶定义一个需要调度的任务,当然我们在这的话呢,我们需要调度的任务是什么呢?呃,就是我们刚才写的那个simple job对吧,非常简单的任务,然后玩job,等于一个new job。
20:53
然后括号simple job.class对吧,当然这个new job呢,呃,我们是需要把它导进来的,哎,我们把这个静态方法呢,直接给它导进来好,呃,New job导进来之后呢,我们。
21:07
需要,呃,当然你可以看到这个new job呢,它是一个simple job,对吧,我们把它点class,呃,也就是说把把它的反射信息呢,给它传进来,然后传进来以后呢,我们在这儿我们要设置任务。ID和任务组对吧,你需要设置一个这个东西来作为他的唯一标识信息对吧,那么这个就是my job对吧,比方说他的ID是my job,然后呢,他的任务组呢是GROUP1对吧,然后点build,哎,这样的话呢,我们一个。呃,需要调度的任务呢,我们就定义好了,其实就是这个simple job,只不过我们要给它起一个名字,然后给它分一下组,然后除了定一个需要调度的任务呢,我们还需要定义什么的触发器,对吧?你这个任务你已经调度,嗯,已经定义好了,其实它类型叫job detail,也就是呃,任务详情,那么你还需要去定义什么呢?我还需要去定义触发器,这个触发器是什么呢?对吧,比方说你这个任务。
22:13
他是一个C任务对吧。还是一个周期性的定时任务呢,对不对,我们就需要去定一个触发器。对吧,来设置它的,呃,这个定时任务它的一个,对吧,你是什么样的一个定时任务,实际上就是在触发器这里来进行配置的,那就是trigger等于new trigger对吧?当然这个也是一个静态方法,你可以把它。呃,直接导进来对吧,直接把它导进来,那这个也是跨里面的好。OK。然后new trigger以后呢,我们还我们要给这个对吧,设置触发器ID和触发器组,那这个我们也需要给它设置一下呃,触发器的ID和组,当然我这个触发器的ID呢,叫或者说它名字呢,叫做买trigger,然后呢,它属于呢GROUP1这个组,然后star now对吧?那这个表示什么呢?立即执行,除了立即执行以外呢,我们还有一个with schedule。
23:25
那么with schedule这里边的话呢,我们给他传一个什么样的参数呢?那就是simple schedule,也就是简单调度,对吧?什么叫做简单调度呢?呃,这里的简单调度意思就是它是一个。周期执行的这样的一个任务,对吧?那在这的话呢,比如说我在这儿with interval in seconds,比方说这写一个五,那这个表示什么呢?这个就表是每隔五秒钟执行一次对吧?呃,就是每五秒钟执行一次,那这个就是我们的一个定时任务对吧?在这的话呢,是每隔五秒钟执行一次对吧?也就是说当我开始调,当我调度这个任务的时候呢,首先它要立即执行,然后呢,接下来呢,就是每过五秒钟呢执行一次。
24:20
然后repeat forever,那这个表示什么呢?表示永久执行对吧,也就是说一直执行下去,当然他除了repeat forever以外呢,还可以比方说呃,它还有一些别的这样的一些repeat对吧?呃,你还可以说with repeat对吧,我就说我我这个每隔五秒钟执行一次,我还可以给他设置一下,比如说我只执行十次对吧,这也是可以的。对吧,这也是可以的,那么一般来说的话呢,就是repeat forever,对吧,也就是说我们呃,永远执行下去对吧?好,那这个的话呢,我们的触发器呢,也就给它,呃,就是说定义好了对吧,那么触发器定义好以后呢,呃,我们给他build一下,OK,那我们现在任务定义好了,触发器定义好了,那我们就可以正式的开始来进行调度了,对吧,那就是schedule job,然后呢,Job trigger。
25:24
对吧,Job trigger调度任务。好,我们现在我们就可以来运行一下这个程序,看一下它这个simple job,它是不是一运行它就打印一次任务被触发执行,然后呢,又每过五秒钟呢,来打印一次,对吧?我们先来看一下我们执行一下,看一下它可不可以运行成功,对吧?可不可以运行成功。好,诶,你可以看到他立马执行的一个任务被触发,然后我们过五秒钟看他会不会执行,哎,那你可发现。
26:02
对吧,它每隔五秒钟就执行一次,对吧,每隔五秒钟就执行一次,当然在这里边要注意的是什么呢?我们并没有把这个任务呢,给它持久化下来,对吧?任务和触发器我们并没有给它持久化下来,呃,如果大家想要持久化的话呢,呃,可以。百度对吧,搜一下或者说看一下的官方文档,因为这个东西本身是很简单的一个事情,就是呃,其实就是在呃MYSQL里面建几张表,然后写下配置文件就可以,呃就是说把这个任务持久化下来,也就是这个跨S呢,它本身是比较易用的,对吧,它本身比较用的,呃,所以说它在Java里边呢,呃它可以说是最著名的一个定时人物调度器,对吧,最著名的一个定时人物调度器啊,你甚至可以基于它来实现呃,Dag的调度器其实也是没有问题的,对吧,好。啊,那我们现在的话呢,我们就大致的学习了呀,跨S这样的一个定时任务调度器,那你学了这个以后呢,其实类似于Java timer呀,包括一些什么,呃,Spring boot,它自己也有调度器,对吧?你其实应该都能大致理解它的工作原理了,对吧,都能大致去呃理解它的工作原理了,呃,那么我们理解底层原理是是相对来说是比较重要的,对吧?我们一会儿的话呢,我们就正式来开发一个非常非常简单的定时任务调度器,对吧,非常非常简单的呃,定时任务调度器,那么你开发完以后呢,你大致就明白说,哎,像doin schedule这样,呃这样的东西,呃,它怎么样被开发出来,对吧,它是怎么样被开发出来的。
27:41
好,那我们把这个定时任务呢,给它停掉。OK,那么在这个包里边的话呢,我们就不写别的代码了,因为它就是一个跨次的一个什么呀,教学的这样的一个,呃,简单的事例对吧,简单的事例。
我来说两句