首先我们要了解一下什么是任务调度,调度就是将一个任务套上一个时间,让该任务可以在时间规律上去循环执行。一般的技术quartz、spring task、java.util.Timer,这几种如果在单一机器上跑其实问题不大,但是如果一旦应用于集群环境做分布式部署,就会带来一个致命的问题,那就是重复执行,当然解决方案有,但是必须依赖数据库,将任务执行状态持久化下来。所以当当就把quartz和zookeeper结合起来达到分布式调度,并且添加其他功能,形成了elastic-job
job类型分为 SimpleJob 简单任务、Dataflow类型作业、Script类型作业
xxl-job与elastic-job 对比
轻量级分布式任务调度框架,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。开箱即用;
界面、可配、弹性、灵活
提供管理界面,方便动态添加、编辑任务及执行器(要定时执行的方法)、多语言 多策略 利用线程池 且加入安全因素可自动报警,根据执行器个数自动分片执行任务;支社区QQ群支持,文档比较详尽;
轻量级无中心化解决方案 ,社区QQ群支持,文档比较详尽,主节点配置分片到zk中分发;一个分片只能放一个job实例(之前看的网页,准确性未知);
使用方式和quartz相似,添加了zk做心跳检测、协调任务分配,实现“故障转移”(节点挂了,其他节点主动抓取未分配的分片内的数据,并且在某台服务器下线后主动寻找可用的服务器执行任务,不过需要等下一次任务执行时才执行这些分片内的job);zk选主过程中阻塞任务,分片结束才能执行任务;失效转移功能,在某台服务器执行完毕后主动抓取未分配的分片;
基本概念
1. 分片概念
任务的分布式执行,需要将一个任务拆分为多个独立的任务项,然后由分布式的服务器分别执行某一个或几个分片项。
例如:有一个遍历数据库某张表的作业,现有2台服务器。为了快速的执行作业,那么每台服务器应执行作业的50%。 为满足此需求,可将作业分成2片,每台服务器执行1片。作业遍历数据的逻辑应为:服务器A遍历ID以奇数结尾的数据;服务器B遍历ID以偶数结尾的数据。 如果分成10片,则作业遍历数据的逻辑应为:每片分到的分片项应为ID%10,而服务器A被分配到分片项0,1,2,3,4;服务器B被分配到分片项5,6,7,8,9,直接的结果就是服务器A遍历ID以0-4结尾的数据;服务器B遍历ID以5-9结尾的数据。
2. 分片项与业务处理解耦
Elastic-Job并不直接提供数据处理的功能,框架只会将分片项分配至各个运行中的作业服务器,开发者需要自行处理分片项与真实数据的对应关系。
核心理念
1. 分布式调度
Elastic-Job-Lite并无作业调度中心节点,而是基于部署作业框架的程序在到达相应时间点时各自触发调度。
注册中心仅用于作业注册和监控信息存储。而主作业节点仅用于处理分片和清理等功能。
2. 作业高可用
Elastic-Job-Lite提供最安全的方式执行作业。将分片总数设置为1,并使用多于1台的服务器执行作业,作业将会以1主n从的方式执行。
一旦执行作业的服务器崩溃,等待执行的服务器将会在下次作业启动时替补执行。开启失效转移功能效果更好,可以保证在本次作业执行时崩溃,备机立即启动替补执行。
3. 最大限度利用资源
Elastic-Job-Lite也提供最灵活的方式,最大限度的提高执行作业的吞吐量。将分片项设置为大于服务器的数量,最好是大于服务器倍数的数量,作业将会合理的利用分布式资源,动态的分配分片项。
例如:3台服务器,分成10片,则分片项分配结果为服务器A=0,1,2;服务器B=3,4,5;服务器C=6,7,8,9。 如果服务器C崩溃,则分片项分配结果为服务器A=0,1,2,3,4;服务器B=5,6,7,8,9。在不丢失分片项的情况下,最大限度的利用现有资源提高吞吐量
整体架构图
实现原理
弹性分布式实现
第一台服务器上线触发主服务器选举。主服务器一旦下线,则重新触发选举,选举过程中阻塞,只有主服务器选举完成,才会执行其他任务。
某作业服务器上线时会自动将服务器信息注册到注册中心,下线时会自动更新服务器状态。
主节点选举,服务器上下线,分片总数变更均更新重新分片标记。
定时任务触发时,如需重新分片,则通过主服务器分片,分片过程中阻塞,分片结束后才可执行任务。如分片过程中主服务器下线,则先选举主服务器,再分片。
通过上一项说明可知,为了维持作业运行时的稳定性,运行过程中只会标记分片状态,不会重新分片。分片仅可能发生在下次任务触发前。
每次分片都会按服务器IP排序,保证分片结果不会产生较大波动。
实现失效转移功能,在某台服务器执行完毕后主动抓取未分配的分片,并且在某台服务器下线后主动寻找可用的服务器执行任务。
servers节点
作业服务器信息,子节点是作业服务器的IP地址。可在IP地址节点写入DISABLED表示该服务器禁用。 在新的cloud native架构下,servers节点大幅弱化,仅包含控制服务器是否可以禁用这一功能。为了更加纯粹的实现job核心,servers功能未来可能删除,控制服务器是否禁用的能力应该下放至自动化部署系统。
leader节点
作业服务器主节点信息,分为election,sharding和failover三个子节点。分别用于主节点选举,分片和失效转移处理。
leader节点是内部使用的节点,如果对作业框架原理不感兴趣,可不关注此节点。
作业启动
作业执行
Elastic-Job的任务分片策略,目前提供了三种任务分片策略,分片策略的实现最终是在注册中心zk中在分片的instance中写入实例信息。
Elastic-Job的定时任务执行机制还是基于quartz开发的,因此Elastic-Job实现了Quartz的任务接口Job实现了LiteJob,来根据定时任务规则执行定时任务。
Elastic-Job提供了任务执行器抽象类AbstractElasticJobExecutor,在AbstractElasticJobExecutor中会获取任务分片信息及任务失败转移等处理操作
在execute中会获取所有的分片信息,及一系列的处理操作。
在execute中会记录一些任务的状态信息,然后执行process方法
在process方法中,会根据分片数量单任务时直接执行,多任务时添加到线程池执行
Elastic-Job中当某个服务器节点与注册中心断开连接(无法进行任务执行)时其需要执行的任务转移到其他节点的过程。
一、重新分片
当服务器节点从注册中心zk断开连接时,Elastic-job需要做的一件事情是需要在下次任务执行前进行重新分片,当zk节点数目发生变更时,会引发ListenServersChangedJobListener监听器调用,此监听器会调用shardingService的重新分片标志设置方法,这样再下次任务执行前会重新进行任务分片操作。
二、任务失效转移
所谓失效转移,就是在执行任务的过程中遇见异常的情况,这个分片任务可以在其他节点再次执行。这个和上面的HA不同,对于HA,上面如果任务终止,那么不会在其他任务实例上再次重新执行。Job的失效转移监听来源于FailoverListenerManager中JobCrashedJobListener的dataChanged方法。FailoverListenerManager监听的是zk的instance节点删除事件。如果任务配置了failover等于true,其中某个instance与zk失去联系或被删除,并且失效的节点又不是本身,就会触发失效转移逻辑。首先,在某个任务实例elastic-job会在leader节点下面创建failover节点以及items节点。items节点下会有失效任务实例的原本应该做的分片好。比如,失效的任务实例原来负责分片1和2。那么items节点下就会有名字叫1的子节点,就代表分片1需要转移到其他节点上去运行
当节点任务失效时会调用JobCrashedJobListener监听器,此监听器会根据实例id获取所有的分片,然后调用FailoverService的setCrashedFailoverFlag方法,将每个分片id写到/jobName/leader/failover/items下
然后接下来调用FailoverService的failoverIfNessary方法,首先判断是否需要失败转移,如果可以需要则只需作业失败转移。
在needFailover方法会对是否需要失效转移进行判断