每台虚机在同一时间都会执行定时任务:html
Tomcatgit |
Nginxspring |
Tomcatshell |
尝试解决:将任务单独拆出放入一台虚机(TASK)。架构
Nginx并发 |
Tomcatapp |
TASK框架 |
Tomcat分布式 |
产生新的问题:性能
1.即使TASK 100%可靠永远不宕。也有极大的停机风险,不肯定在停机期间是否有任务被遗漏(misfire)。
2.任务更多,更复杂,占愈来愈多的资源,性能问题凸显,任务队列阻塞风险。
Nginx |
Tomcat |
Tomcat |
DB(quartz) |
以后看了眼quartz官方logo,感受本身萌萌的。
萌不过三天。发现这个定时任务策略要修改,
一样,下面这个任务不须要作,取消掉
也没法及时监控:报错了吗,运行成功了吗?
随着业务发展暴露出愈来愈多的问题:
例如:
----截图摘自沈建林“分布式调度系统介绍”中的五个问题
集思广益造轮子:
Quartz,Xxl-job,elastic-job,tbschedule,uncode-schedule,Opencron
在分布式环境中如何将任务集群中分散的、可靠性差的任务统一化管理和调度,实现分布式部署的管理方式,这就是分布式任务调度。
http://www.javashuo.com/article/p-onabuvoj-bc.html
XXL-JOB框架2015-11月发布1.0.RELEASE。
2016-01月,大众点评接入XXL-JOB,内部别名《Ferrari》。 自2016-01-21接入至2017-12-01期间,该系统已调度约100万次,通过数个大版本的更新,系统的任务模型、UI交互模型以及底层调度通信模型都有了较大的优化和提高,核心功能更加稳定高效。
Elastic-Job分为Elastic-Job-Lite和Elastic-Job-Cloud
http://code.taobao.org/p/tbschedule/src/
http://code.taobao.org/p/tbschedule/wiki/tbschedule-quick-start/
https://gitee.com/uncode/uncode-schedule/releases
2.2.1.1.1Example1
固然也支持cron表达式以下,运行结果略。
2.2.1.1.2Example2-CronTrigger Misfire
Misfire策略
withMisfireHandlingInstructionDoNothing:不触发当即执行,等待下次调度; withMisfireHandlingInstructionIgnoreMisfires:以错过的第一个频率时间马上开始执行; withMisfireHandlingInstructionFireAndProceed:以当前时间为触发频率马上触发一次执行;
准备工做:
Job:
Misfires strategy1:
withMisfireHandlingInstructionIgnoreMisfires:以错过的第一个频率时间马上开始执行;
Misfires strategy2:
withMisfireHandlingInstructionDoNothing:不触发当即执行,等待下次调度;
Misfires strategy3:
withMisfireHandlingInstructionFireAndProceed:以当前时间为触发频率马上触发一次执行
2.2.1.2.1Quartz组件
QuartzSchedulerThread :负责执行向QuartzScheduler注册的触发Trigger的工做的线程。
ThreadPool:Scheduler使用一个线程池做为任务运行的基础设施,任务经过共享线程池中的线程提供运行效率。
QuartzSchedulerResources:包含建立QuartzScheduler实例所需的全部资源(JobStore,ThreadPool等)。
SchedulerFactory :提供用于获取调度程序实例的客户端可用句柄的机制。
JobStore: 经过类实现的接口,这些类要为org.quartz.core.QuartzScheduler的使用提供一个org.quartz.Job和org.quartz.Trigger存储机制。做业和触发器的存储应该以其名称和组的组合为惟一性。
QuartzScheduler :这是Quartz的核心,它是org.quartz.Scheduler接口的间接实现,包含调度org.quartz.Jobs,注册org.quartz.JobListener实例等的方法。
Scheduler :这是Quartz Scheduler的主要接口,表明一个独立运行容器。调度程序维护JobDetails和触发器的注册表。 一旦注册,调度程序负责执行做业,当他们的相关联的触发器触发(当他们的预约时间到达时)。
Trigger :具备全部触发器通用属性的基本接口,描述了job执行的时间出发规则。 - 使用TriggerBuilder实例化实际触发器。
JobDetail :传递给定做业实例的详细信息属性。 JobDetails将使用JobBuilder建立/定义。
Job:要由表示要执行的“做业”的类实现的接口。只有一个方法 void execute(jobExecutionContext context)
(jobExecutionContext 提供调度上下文各类信息,运行时数据保存在jobDataMap中)
Job有个子接口StatefulJob ,表明有状态任务。
有状态任务不可并发,前次任务没有执行完,后面任务处于阻塞等到。
2.2.1.2.2组件关系简要
2.2.1.2.3生命周期
只列重点不展开,用Quartz官网Example1
2.2.1.2.3.1Scheduler
(1)Scheduler
Instantiate()这是一个近千行的方法,
(1-1)Scheduler Members
(2)JobStore
(3)ThreadExecutor
(4)QuartzSchedulerThread
(4-1)run()
(4-2)sigLock.await()
(5)Job run
2.2.1.2.3.2Scheduler-start()-notifyAll()
2.3.1.1.1JobStore
2.3.1.1.2Lock & Trigger
2.3.1.1.3时序图
2.3.1.2.1功能概述
2.3.1.2.2架构
Nginx |
Tomcat |
Tomcat |
Zookeeper |
Spring task |
Quartz |
2.3.1.2.3ZKScheduleManager
继承ThreadPoolTaskScheduler,重写下图方法:
在子类和父类中任选一个方法对比,好比scheduleAtFixedRate()方法:
子类:
父类:
发现便是在第一个入参Runnable task包装了一个taskWrapper(task)
在容器启动以及心跳刷新服务的时候,会在zookeeper上建立节点
在节点
”/uncode_test/schedule/task/helloWorld#hi”
下面会有ip+uuid+seqno,在taskWrapper()中的isOwner便是根据此标识字符串:
“192.168.236.1$FA2165482C644A899076A9542BF68C25$0000000008”
每一个机器本身均持有各自的标识字符串,任一时刻至多只有一台匹配的机器,持有匹配字符串的机器才能执行
2.3.1.2.4心跳-刷新任务节点
2.3.1.2.5Uncode schedule与Quartz集成
2.3.1.2.6监控
2.3.1.3.1配置
2.3.1.3.2任务/分片 demo
2.3.2.1.1功能概述
http://www.javashuo.com/article/p-onabuvoj-bc.html
2.3.2.1.2调度关系
Jetty |
Admin |
Xxl-job-core.jar |
Jetty |
2.3.2.1.3管理中心
路由策略
2.3.2.1.4管理端服务AdminBiz
XxlJobDynamicScheduler
服务发现+失败预警+远程触发
JobRegistryMonitorHelper.getInstance().start();
执行器注册到registry,管理中心不断扫描同步注册进来的执行器至group中。
Server Registry |
Admin |
Executor |
Server Group |
JobFailMonitorHelper.getInstance().start();
(3)RemotehttpJobBean
参见Uncode-Schedule与Quartz集成
(4)XxlJobTrigger策略模式按策略触发任务
(5)NetComClientProxy代理模式远程调用Executor
(6)路由策略
(6-1)第一个
(6-2)一致hash
(6-3)分片广播
对比其它策略的相同方法:
(6-4)failover
(6-5)busyover
(6-5)其它
其它策略:最后一个,轮询,随机,最不常用,最近最久不使用:略。
也可本身定制。
(7)Misfire
XXL-JOB默认misfire规则为:withMisfireHandlingInstructionDoNothing
2.3.2.1.5执行器端服务ExecutorBiz
(1)XxlJobExecutor
(1-1)NetComClientProxy代理模式远程调用Admin
(1-2)加载任务bean
(1-3)服务注册
(2)JettyServerHandler准备执行任务
(3)ExecutorBizImpl如何执行任务
(4)TriggerParam
抢占式:谁先得到资源谁就能执行,这种模式没法将单个任务的数据交给其它节点协同处理,通常用于处理数据量较小,任务较多的场景下。
协同式:能够将单个任务处理的数据分配到多个JVM中处理,提升数据的并行处理能力,可以充分利用计算机资源。
TbSchedule:
Uncode schedule:
TbSchedule:
Uncode schedule:
做业分片只是个逻辑概念,分片和实际数据其实框架是不作任何匹配关系的。而根据分片项和实际业务如何关联按业务自定义。