- 基本情况
elastic-job是当当开源的一款非常好用的作业框架,在这之前,我们开发定时任务一般都是使用quartz或者spring-task(ScheduledExecutorService),无论是使用quartz还是spring-task,我们都会至少遇到两个痛点:
1.不敢轻易跟着应用服务多节点部署,可能会重复多次执行而引发系统逻辑的错误。
2.quartz的集群仅仅只是用来HA,节点数量的增加并不能给我们的每次执行效率带来提升,即不能实现水平扩展
- 产品说明
elastic-job在2.x之后,出了两个产品线:Elastic-Job-Lite和Elastic-Job-Cloud。我们一般使用Elastic-Job-Lite就能够满足需求,本文也是以Elastic-Job-Lite为主。1.x系列对应的就只有Elastic-Job-Lite,并且在2.x里修改了一些核心类名,差别虽大,原理类似,建议使用2.x系列
- 原理
举个典型的job场景,比如营销活动的清盘,系统需要job在每天晚上执行,对需要清盘的活动进行全部清盘。如果数据不多,我们可以轻易使用quartz来完成,我们让计息job在某个时间点开始执行,这没问题。可是,如果数据体量特别大,我们可能会面临着在第二天之前处理不完这么多数据。另外,我们部署job的时候也得注意,我们可能会把job直接放在我们的webapp里,webapp通常是多节点部署的,这样,我们的job也就是多节点,多个job同时执行,很容易造成重复执行,比如用户重复计息,为了避免这种情况,我们可能会对job的执行加锁,保证始终只有一个节点能执行,或者干脆让job从webapp里剥离出来,独自部署一个节点
elastic-job就可以帮助我们解决上面的问题,elastic底层的任务调度还是使用的quartz,通过zookeeper来动态给job节点分片,如果某一个IP机器节点挂了,该机器的分片任务就会分配到其他IP机器上,实现弹性扩容
- 分片配置
目前有一下实现类
①AverageAllocationJobShardingStrategy:基于平均分配算法的分片策略,如果分片不能整除, 则不能整除的多余分片将依次追加到序号小的服务器
如果有3台服务器, 分成9片, 则每台服务器分到的分片是: 1=[0,1,2], 2=[3,4,5], 3=[6,7,8].
如果有3台服务器, 分成8片, 则每台服务器分到的分片是: 1=[0,1,6], 2=[2,3,7], 3=[4,5].
如果有3台服务器, 分成10片, 则每台服务器分到的分片是: 1=[0,1,2,9], 2=[3,4,5], 3=[6,7,8].②OdevitySortByNameJobShardingStrategy:根据作业名的哈希值奇偶数决定IP升降序算法的分片策略.
首先 作业名的哈希值为奇数则IP升序. 作业名的哈希值为偶数则IP降序.然后再调用AverageAllocationJobShardingStrategy的平均分片算法进行分片
③RotateServerByNameJobShardingStrategy:根据作业名的哈希值对服务器列表进行轮转的分片策略④自定义分片
- 作业类型
简单作业SimpleJob、数据流作业DataflowJob、脚本作业ScriptJobs三种任务
①SimpleJob
cron :cron表达式,用于控制作业触发时间。
shardingTotalCount :作业分片总数
shardingItemParameters :分片序列号和参数用等号分隔,多个键值对用逗号分隔分片序列号从0开始,不可大于或等于作业分片总数 如:0=a,1=b,2=c
jobParameters :作业自定义参数,可通过传递该参数为作业调度的业务方法传参,用于实现带参数的作业
问题一:当你jobName相同,修改其它参数时,你会发现,重新启动应用执行并没有生效,依然保留原有参数。这是因为?
原因:zookeeper 注册中心会持久化这个分片相关信息。解决办法:overwrite设置为true即可,如下设置
②DataflowJob
也许你有一大堆数据要处理,用simple略显得麻烦些,那么就可以用DataflowJob。
业务实现包含两个接口:抓取(fetchData)和处理(processData)数据
流式处理数据只有fetchData方法的返回值为null或集合长度为空时,作业才停止抓取,否则作业将一直运行下去;
非流式处理数据则只会在每次作业执行过程中执行一次fetchData方法和processData方法,随即完成本次作业③ScriptJob脚本作业,一般不用
- 配置实现
引入jar包,配置zk,配置job参数,定义job实现
- 具体使用