1.写在前面
elastic-job是当当开源的一款非常好用的作业框架,在此之前,任务调度的主流框架是quartZ或者spring-task。两者均不能很好地支持高并发量的分布式任务调度,即使是号称拥有集群能力的quartZ也仅仅保证了job的高可用,单一时刻只能有一台机器执行具体的调度任务。因此,老牌劲旅无法解决两个迫切的需求点:
1.quartZ的集群仅仅是用于实现HA(high avalible),无法实现高并发;
2.无论quartZ还是spring-task,均无法很好地实现水平拓展;
Elastic-Job is a distributed scheduled job framework, based on Quartz and Zookeeper.
上述文字是elastic-job github主页对它的描述,从上面的描述中我们可以看到两个关键字Quartz和Zookeeper,基于以上两个基础框架,Elastic-job实现了高可用和高并发。
2.elastic-job解决了那些问题
举个典型的job场景,比如余额宝里的昨日收益,系统需要job在每天某个时间点开始,给所有余额宝用户计算收益。如果用户数量不多,我们可以轻易使用quartz来完成,我们让计息job在某个时间点开始执行,循环遍历所有用户计算利息,这没问题。可是,如果用户体量特别大,我们可能会面临着在第二天之前处理不完这么多用户。另外,我们部署job的时候也得注意,我们可能会把job直接放在我们的webapp里,webapp通常是多节点部署的,这样,我们的job也就是多节点,多个job同时执行,很容易造成重复执行,比如用户重复计息,为了避免这种情况,我们可能会对job的执行加锁,保证始终只有一个节点能执行,或者干脆让job从webapp里剥离出来,独自部署一个节点。
elastic-job就可以帮助我们解决上面的问题,elastic底层的任务调度还是使用的quartz,通过zookeeper来动态给job节点分片。我们来看:很大体量的用户需要在特定的时间段内计息完成我们肯定是希望我们的任务可以通过集群达到水平扩展,集群里的每个节点都处理部分用户,不管用户数量有多庞大,我们只要增加机器就可以了,比如单台机器特定时间能处理n个用户,2台机器处理2n个用户,3台3n,4台4n...,再多的用户也不怕了。
使用elastic-job开发的作业都是zookeeper的客户端,比如我希望3台机器跑job,我们将任务分成3片,框架通过zk的协调,最终会让3台机器分别分配到0,1,2的任务片,比如server0-->0,server1-->1,server2-->2,当server0执行时,可以只查询id%3==0的用户,server1执行时,只查询id%3==1的用户,server2执行时,只查询id%3==2的用户。任务部署多节点引发重复执行在上面的基础上,我们再增加server3,此时,server3分不到任务分片,因为只有3片,已经分完了。没有分到任务分片的作业程序将不执行。如果此时server2挂了,那么server2的分片项会分配给server3,server3有了分片,就会替代server2执行。如果此时server3也挂了,只剩下server0和server1了,框架也会自动把server3的分片随机分配给server0或者server1,可能会这样,server0-->0,server1-->1,2。这种特性称之为弹性扩容,即elastic-job名称的由来。
上述的引用比较冗长,简单地理解就是elastic-job利用zk的分布式集群管理能力,对job节点进行的弹性扩容和收缩。同时任务分片的方式保证了job执行的并发能力和防止重复执行,使任务调度不仅拥有高可用,也具备了水平拓展和高并发能力。
3.elastic-job结构
3.2 elastic-job架构图
3.3 任务节点数据结构
4.elastic-job模块简析
core的主要的模块分为:
job模块:plugin(内含三种不同的作业类型,分片策略),api(对外暴露的api服务),exception(异常类),internal(内部模块)
reg(注册中心)模块:base(基类),异常处理模块,zookeeper注册中心模块