作业调度框架(第一个自己设计并进行了实际编码的框架)

       Spring中有用于开启定时任务的@Scheduled注解,该注解的使用也十分的简单,只需要在注解内定义好调度策略,然后写好业务逻辑,Spring会自动将其作为一个定时作业进行执行。初学@Scheduled注解时,感觉使用起来确实很爽,但是在分布式场景下,服务会被部署多次,此时如果定时任务触发,就会导致作业多次执行,也就是多数据进行了多次处理,最后的结果就是导致数据被污染。

       “当当有个elastic-job可以解决这个问题。它的思路就是。。。。。你们有兴趣可以研究一下”

       我美滋滋的去看了下,很优秀,但是我觉得或许还有更高效的方式,因为elastic-job包含选主及任务分配,而且它的弹性扩容实际比较坑,并且还有其他别的我感觉不是很合理的小问题。搜了下这个问题的解决方案,发现还有个Quartz,也是做这个的,网上有人说elastic-job用的Quartz的东西(原话不是这个,但是是类似的意思),我就没看Quartz,直接跳过了。犹豫了一下后,我决定自己去写一个小框架。

       一开始我本来是想复用Spring的@Scheduled注解,做了一天以后我发现,复用Spring内部的东西还是有难度的,而且如果Spring以后的版本对@Scheduled注解的处理发生改变,我写的这个小破框架就要跟着改,这样与Spring耦合度太高,解耦很重要,能不能彻底分开呢?跟Spring总是要有交互的(不交互也行,但是可能使用起来就没那么简单了),所以耦合度只能降低,不能根除。虽然Spring是不断变化的,但是其内部一些基本的东西是不会变的(比如BeanPostProcessor和Listener),可以利用这些不会变化的东西进行开发,所以我就用了BeanPostProcessor和Listener(其实只用BeanPostProcessor或者只用Listener就可以)。

不多说,先介绍用法。只需要在相应的方法上添加如下注解即可(注解中的所有属性都有相对来说最为合理的默认值,可以根据自己的需求进行定制,如果不显式的指定每个属性的值,将采用默认值):

@ScheduleJob(cron="2018-03-31,22",jobName=“updateBalance”type=ScheduleJobType.SIMPLE, retryTimes=5,size=1000,multithreads=1,isolatedMultithreads=1,baseOnResourceUsage=false,mode= ScheduleJobMode.DISTRIBUTEignoreData="{}")

各属性说明:

        cron:调度策略的表达式,不多解释。已实现。

        jobName:作业名。如果不显式指定该项的值,默认会使用使用了该注解的方法的方法名作为作业名称。已实现。

        type:作业类型。目前暂定两种:SIMPLE("simple"),DATA_FLOW("dataflow");默认是SIMPLE。已实现一半。

        retryTimes:并不是每个作业分片都能成功处理,如果作业分片处理失败,就直接被列为失败任务吗?好像不太合理,因为有时失败的原因可能是存在某个节点网络出现问题、或者出现宕机的情况,这个时候因为失败一次就直接被列为失败任务,不太合理。所以设置了这么个属性来由开发人员自定义失败重试次数,这次失败了?没问题,换个节点再来。默认是重试3次。已实现。

        size:单个作业分片的大小。一个定时作业规模可能很大,比如有10亿条数据需要处理,我们需要对它进行分片,每片的数据量固定大小,使得每个作业分片大小相同,size就是指这个大小。默认为1000。已实现。

        isolatedMultithreads:线程多开(区别于多线程):单节点开启几个线程去跑某个作业。比如前面说有10亿条数据(一般规模很大的作业可能不会由系统去做,而是通过MR或者Spark/Flink做处理,我在这只是举一个例子),使用默认分片大小的话,就有100万个作业分片需要去执行,但是我们现在只有20个节点,也就是说,每个节点要处理5万个作业分片。如果每个节点只开启一个线程去执行作业,就算是一个作业分片每个都只需要1S,那也需要5万秒,就是将近十五个小时,那系统别干别的了,就做这个吧。这种情况下,就可以通过threads属性来指定每个节点执行作业的线程数,如果每个节点开启五个线程,那么10亿条数据20个后台实例就可以三个多小时执行完。。啰嗦一点儿:这种模式下线程之间完全是独立的,每个线程在执行任务时获取到的数据分片是不共享的,也就是说,独立线程多开就是一台机器上创建多个完全隔离的线程,每个线程都执行一个调度任务(这种适合服务器压力不是很大,空闲资源能够满足多独立线程的需求)。默认为1,也就是每个节点只有一个线程参与任务的执行。已实现。

       Multithreads:指传统的多线程,因为有时候一个任务分片可能要处理很长时间,此时可以使用多线程的方式去处理获取到的数据分片,此时需要分为获取数据分片的线程和具体处理数据的线程,比如A线程负责获取任务分片,A、B、C、D线程是具体处理数据的线程(A本身既获取数据分片又参与任务调度),他们共享A线程获取到的数据分片。默认为1,也就是只有一个线程消费获取到的数据分片。未编码实现。

       baseOnResourceUsage:基于服务器当前资源使用率来决定是否参与任务执行,或者如果配置了独立线程多开或多线程的话,可以根据资源使用率来决定启动多少个线程参与调度,避免出现因为执行定时任务而导致服务器直接宕机的情况。资源使用率包括CPU使用率、内存使用率和网络带宽使用率。比如,如果某一时刻服务器CPU使用率达到了90%或内存使用率达到了90%或网络带宽使用了90%或者网络压根就不通了,此时会根据具体的使用率来调整该节点到底如何参与本次任务调度。已实现。

       mode:DISTRIBUTE和STAND_ALONE。有时需要定时执行的任务体量很小,采用分布式调度反而会变慢。(比如每次调度触发时数据只有100条左右,这是根本没有必要采用分布式模式),此时可以采用单机模式(STAND_ALONE)模式,在该模式下,每次任务触发时,每个节点都会向注册中心注册,第一个注册到的有效,其他无效。但是最好是先获取下当前节点的资源使用情况,根据资源使用率来决定是否参与本次任务,比如当前节点正在执行其他任务,导致本节点资源占用率非常高,此时就禁止本节点向注册中心注册。默认采用DISTRIBUTE,即分布式模式。已实现。

       ignoreData:有时需要忽略一些数据,只处理被忽略数据后的数据,此时就可以设置需要忽略的数据量。已简易实现。

       在数据分片时是自动分片,可以基于ZooKeeper,也可以基于Redis,基于Zookeeper的实现比基于Redis的实现要复杂的多,在一开始写这个框架的时候,为了锻炼自己的逻辑能力和编程能力,我用的是基于ZooKeeper的实现。现在使用的话就是在配置文件中写好ZooKeeper集群地址、ZK超时时间等即可。(默认是在schedulejob.properties配置文件中进行配置)。

       使用了该注解的方法会被封装成一个ExecutorModel。如果该注解放在类上说明该类的每个方法都是一个调度作业,这些调度作业拥有相同的调度策略(拥有相同的cron属性)。但是不建议放在类上,因为多个作业共用同一套调度策略会导致系统负载过大。也可以同时放在类和方法上,此时用在方法上的注解的属性会覆盖用在类上的注解的属性,如果方法注解中某个属性没有配置,而类上的注解中配置了,则用类上的注解配置的属性,如果都没有,则使用默认值。

       elastic-job需要选主,然后由主节点对作业进行分片,各节点执行作业分片。主节点挂了,重新选主重新分片;如果有新的节点在作业分好片后加进来,不好意思,这次干活没你的份,下次再带你玩。

       这个@Schedled就很吊了,不选主,自动对作业进行分片(就是自己给自己分,多节点之间还不会重复)。而且不管什么什么时候加进来,只要你的任务处于触发状态,随时都可以执行作业分片;不管什么时候退出,你的作业会立刻被认为执行失败(事务要控制好),会有其他节点根据配置的重试次数再次执行你的这个任务,直到执行成功或者失败次数超过重试次数为止。

       现在只是实现了简单任务(SIMPLE("simple"))基于ZooKeeper的实现,大头还没有真正去做,而且没有实际使用,只是三个节点进行过测试,最终数据显示没什么问题。(吐槽一下,我电脑太古老了,启动三个Tomcat竟然崩了一个,辛亏有日志为证,要不然我还以为我写的代码有问题)。

       以后会做DATA_FLOW的处理逻辑。

       而且会提供基于数据库的实现,因为基于数据库的话,可以记录处理结果(譬如什么时间哪个作业分片在哪个节点上执行失败/成功,失败原因是什么,成功的话用了多少时间;失败的任务分片后来又被哪个节点执行了等等。其实基于ZooKeeper也可以实现,但是ZK一般只存少量数据,存储大量数据可能会导致ZK集群爆炸),然后做一个管理后台,可以通过后台直接查看作业的执行情况和进度。还会添加是否设置自动延时等。

       目前的实现在设计风格上都尽量遵循SpringBoot,因为万一哪天真的做出来了,肯定是要做成SpringBoot的starter。

       具体代码,就在同性交友网站上,可以直接fork,等我哪天完全做完、测试没问题了,然后再完整开源。

       这个东西现在还没起名字,各位可以帮忙取个名字,啥名字都行,因为反正我也不会用你们起的名字,你们爱起什么就起什么。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我! 毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青草绿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值