Name | 描述 |
---|---|
JobRegistry | job注册表 |
GuaranteeService | 保证分布式任务全部开始和结束状态的服务 |
ElasticJobListener | 弹性化分布式作业监听器接口 |
JobScheduler | 作业调度器. |
JobNodeStorage | 作业节点数据访问类 |
JobScheduleController | 作业调度控制器,其实就是quartz的scheduler |
config 节点
代表了这个job的配置信息,如果app启动的时候没有设置override=true && zk上的配置不为空,那么就使用zk已经存在的zk信息,这一点要特别注意,如果改了配置信息,但是没有设置override就会出问题,但是有些信息也可以调节console里面的配置,因为他是以zk为准的。
配置参数
Name | 描述 |
---|---|
monitorExecution | 默认是true,当job触发的时候如果上一次还有分片在运行中则忽略掉本次运行 |
maxTimeDiffSeconds | 任务执行机器和zk机器的时间差,如果设置了不是-1,那么两者误差要在这个范围内,否则启动报错,但是只是记到了错误日志,启动还是可以继续的 |
-
每个sharding节点下的子节点有哪些?
- instance 节点,记录了这个分片执行的instance的ip、pid
- running
- misfire
- disabled
- failover 节点,表示这个分片原来是运行在实例上的的后来失败被转义到别的实例上的
-
重新分片
在每次执行任务的时候,有一个步骤是获取分片上下文,这个时候会检查是否需要重新分片。- 如何确定是否需要分片呢?
当监听到分片总数变化、实例数量变化、分布式作业不一致、注册作业启动信息的时候会创建需要重新分片的节点 :leader/sharding/necessary
只有存在这个节点,才可能开始下面的分片逻辑:
- 如何确定是否需要分片呢?
分片
- 如果当前实例是leader节点,他会等待所有的分片都执行完成后,创建 /leader/sharding/processing 节点,表示分片动作正在执行中,那么非leader节点看到存在这个节点就会一直等着不会继续执行,leader节点首先重置所有的分片信息,例如原来是 0,1,2三个分片,现在分片0,1 那么就会把2删掉,接着使用分片策略,最后形成
Map<JobInstance, List<Integer>> 这个结构,最后将每个分片下面的instance节点的值写为对应实例的id。最后删除/leader/sharding/necessary 和 /leader/sharding/processing 节点
- 如果当前实例是leader节点,他会等待所有的分片都执行完成后,创建 /leader/sharding/processing 节点,表示分片动作正在执行中,那么非leader节点看到存在这个节点就会一直等着不会继续执行,leader节点首先重置所有的分片信息,例如原来是 0,1,2三个分片,现在分片0,1 那么就会把2删掉,接着使用分片策略,最后形成
- 如果当前实例不是leader节点,就一直等到分片完成在继续执行,然后
misfire
misfire 在quartz里的原因是cron设置的执行间隔很小,但是任务执行的时间很长,导致下一次触发执行的时候上一次的任务还没有执行完成,这样本次任务在执行的时候发现sharding下面还有running节点,就会设置这个sharding下的misfire节点 ,然后跳过本次执行-
failover
failover 功能指的是当一个实例在执行过程中宕机,可以把分片转移到其他的实例上运行什么时候需要failover?
节点 /leader/failover/items 存在 并且 下面的子节点不为空 并且当前任务没有在运行状态
创建临时节点 sharding/xx/failover
同时删除 /leader/failover/items/xx
立即启动作业 scheduler.triggerJob(jobDetail.getKey());/leader/failover/items 节点以及子节点表示失效的节点,这些节点什么时候创建的呢?
每次执行完成,删除failover节点
-
监听器
app启动的时候会开启这些监听器electionListenerManager
-
shardingListenerManager
- ShardingTotalCountChangedJobListener
分片数量变化,得到通知,更新本地的分片数量缓存,同时创建/leader/sharding/necessary节点 - ListenServersChangedJobListener
如果是server数量变化或者instance数量变化就设创建/leader/sharding/necessary节点
- ShardingTotalCountChangedJobListener
-
failoverListenerManager
监听/jobName , 节点或者数据变化会执行 ,注册了两个zk listener-
JobCrashedJobListener
- 监听节点删除事件,检查 sharding 下的子节点 instance ,如果instaceid和挂掉的机器instanceid是一样的,这样就搜集了挂掉实例上运行的所有分片,如果 /sharding/xx/failover 节点没有创建,那么就创建 /leader/failover/items/xx 节点。
然后创建临时节点 sharding/xx/failover
同时删除 /leader/failover/items/xx
立即启动作业 scheduler.triggerJob(jobDetail.getKey());
- 监听节点删除事件,检查 sharding 下的子节点 instance ,如果instaceid和挂掉的机器instanceid是一样的,这样就搜集了挂掉实例上运行的所有分片,如果 /sharding/xx/failover 节点没有创建,那么就创建 /leader/failover/items/xx 节点。
FailoverSettingsChangedJobListener
监听config配置节点,如果配置改变了(通过控制台改变),如果配置不再支持failover了,那么就删掉所有的 sharding/xx/failover 节点
-
- monitorExecutionListenerManager
- shutdownListenerManager
- triggerListenerManager
- rescheduleListenerManager
- guaranteeListenerManager
- regCenterConnectionStateListener
- 任务状态
- jobStatusTraceEvent
TASK_STAGING
TASK_RUNNING,
TASK_FINISHED,
TASK_KILLED,
TASK_LOST,
TASK_FAILED,
TASK_ERROR,
TASK_DROPPED,
TASK_GONE,
TASK_GONE_BY_OPERATOR,
TASK_UNREACHABLE,
TASK_UNKNOWN
INSERT INTO `JOB_STATUS_TRACE_LOG` (`id`, `job_name`, `original_task_id`, `task_id`, `slave_id`, `source`, `execution_type`, `sharding_item`, `state`, `message`, `creation_time`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
JobStatusTraceEvent
JobStatusTraceEvent
- 线程池
new ThreadPoolExecutor(
threadSize,
threadSize,
5L,
TimeUnit.MINUTES,
workQueue,
new BasicThreadFactory.Builder().namingPattern(Joiner.on("-").join(namingPattern, "%s")).build());
threadPoolExecutor.allowCoreThreadTimeOut(true);
1. 固定大小线程池
2. 允许core线程超时
3. 线程数量 = Runtime.getRuntime().availableProcessors() * 2
-
如果我们自定义的业务逻辑报错会怎么处理
在框架里会catch住,将错误堆栈信息提交到eventbus,并记录到日志。
提供的扩展点
- 默认的线程池是固定大小、线程数量是cpu个数的2倍,对于cpu密集和IO密集不能做区分,因此提供了线程池的扩展点
app启动
- 从zk中获取到config
- xx
- 通过jobProperties 可以设置任务执行的线程池和异常处理策略