(一)Quartz缺点
- 集群环境下任务是怎样觉得在哪一个节点执行的,是随机负载分配的的,是通过数据库去抢占下一个即将触发的Trigger的绑定的任务的权限,所以没有办法去对我们的任务进行协调(自定义的负载规则).
2. 数据库仅仅是共享数据,并没有协调的功能,如果我想选举一个Leader出来,数据库是没办法实现的
3. 任务数量过多的时候,有个Task要处理10万条数据,单线程导致了生产事故的发生,一个任务只能在一个机器节点去执行,那么九个小时就一直在这一个节点去执行,其它三个节点一直很空闲,有没有办法给一个任务拆分成多个子任务在多个机器节点去做负载执行.这就是分片的概念.
比如说10万的数据给分割一下,每个节点都去处理三万多的数据,这是Quartz没办法满足的功能.
4. 同时Quartz没有可视化操作界面,只能程序员去自己手动去做一个页面.
5. 监控统计需求,比如说任务什么时候触发的,触发是否成功,这个Quartz也没有.
(二)Elastic-Job功能特性
1.分布式调度协调:用 ZK 实现注册中心
2. 错过执行作业重触发(Misfire)
3. 支持并行调度(任务分片)
4. 作业分片一致性,保证同一分片在分布式环境中仅一个执行实例
5. 弹性扩容缩容:将任务拆分为 n 个任务项后,各个服务器分别执行各自分配到的任务项。一旦有新的服务器加入集群,或现有服务器下线,elastic-job 将在保留本次任务执行不变的情况下,下次任务开始前触发任务重分片。
6. 失效转移 failover:弹性扩容缩容在下次作业运行前重分片,但本次作业执行的过程中,下线的服务器所分配的作业将不会重新被分配。失效转移功能可以在本次作业运行中用空闲服务器抓取孤儿作业分片执行。同样失效转移功能也会牺牲部分性能。
7. 支持作业生命周期操作(Listener)
8. 丰富的作业类型(Simple、DataFlow、Script)
9. Spring 整合以及命名空间提供
10. 运维平台(三)Elastic-Job发展历史
在当当的 ddframe 框架中,需要一个任务调度系统(作业系统)。
实现的话有两种思路,一个是修改开源产品,一种是基于开源产品搭建(封装),当当选择了后者,最开始这个调度系统叫做 dd-job。它是一个无中心化的分布式调度框架(每个节点都是平等的)。因为数据库缺少分布式协调功能(比如选主),替换为 Zookeeper 后,增加了弹性扩容和数据分片的功能。
Elastic-Job 是 ddframe 中的 dd-job 作业模块分离出来的作业框架,基于 Quartz和 Curator 开发,在 2015 年开源。
Leader作用是配置分片管理的功能
任务类型
(一)SimpleJob
简单实现,未经任何封装的类型。需实现 SimpleJob 接口。
案例:ZJJElastic-Job_2020/06/12 9:37:27_5yq4y |
---|
(二)DataFlow Job
DataFlowJob:Dataflow 类型用于处理数据流,必须实现 fetchData()和
processData()的方法,一个用来获取数据,一个用来处理获取到的数据。
案例:ZJJElastic-Job_2020/06/12 9:37:00_nfp21 |
---|
(三)Script Job
Script:Script 类型作业意为脚本类型作业,支持 shell,python,perl 等所有类型
脚本。
案例:ZJJElastic-Job_2020/06/12 9:37:17_8yklo |
---|
Zookeeper注册中心数据结构
一个任务一个二级节点。
这里面有些节点是临时节点,只有任务运行的时候才能看到。
注意:修改了任务重新运行任务不生效,是因为 ZK 的信息不会更新, 除非把
overwrite 修改成 true。
(一)config 节点
JSON 格式存储。
存储任务的配置信息,包含执行类,cron 表达式,分片算法类,分片数量,分片参
数等等。
{ “jobName”: “MySimpleJob”, “jobClass”: “job.MySimpleJob”, “jobType”: “SIMPLE”, “cron”: “0/2 ?”, “shardingTotalCount”: 1, “shardingItemParameters”: “”, “jobParameter”: “”, “failover”: false, “misfire”: true, “description”: “”, “jobProperties”: { “job_exception_handler”: “com.dangdang.ddframe.job.executor.handler.impl.DefaultJobExceptionHandler”, “executor_service_handler”: “com.dangdang.ddframe.job.executor.handler.impl.DefaultExecutorServiceHandler” }, “monitorExecution”: true, “maxTimeDiffSeconds”: -1, “monitorPort”: -1, “jobShardingStrategyClass”: “”, “reconcileIntervalMinutes”: 10, “disabled”: false, “overwrite”: false } |
---|
config节点的数据是通过ConfigService持久化到zookeeper中去的。默认状态下,
如果你修改了 Job 的配置比如 cron 表达式、分片数量等是不会更新到 zookeeper 上去
的,除非你在 Lite 级别的配置把参数 overwrite 修改成 true。
LiteJobConfiguration simpleJobRootConfig =
LiteJobConfiguration.newBuilder(simpleJobConfig).overwrite(true).build();
(二)instances 节点
同一个 Job 下的 elastic-job 的部署实例。一台机器上可以启动多个 Job 实例,也就
是 Jar 包。instances 的命名是 IP+@-@+PID。只有在运行的时候能看到。
(三)leader 节点
任务实例的主节点信息,通过 zookeeper 的主节点选举,选出来的主节点信息。在
elastic job 中,任务的执行可以分布在不同的实例(节点)中,但任务分片等核心控制,
需要由主节点完成。因此,任务执行前,需要选举出主节点。
下面有三个子节点:
election:主节点选举
sharding:分片
failover:失效转移
election 下面的 instance 节点显示了当前主节点的实例 ID:jobInstanceId。
election 下面的 latch 节点也是一个永久节点用于选举时候的实现分布式锁。
sharding 节点下面有一个临时节点,necessary,是否需要重新分片的标记。如果
分片总数变化,或任务实例节点上下线或启用/禁用,以及主节点选举,都会触发设置重
分片标记,主节点会进行分片计算。
(四)servers 节点
任务实例的信息,主要是 IP 地址,任务实例的 IP 地址。跟 instances 不同,如果多
个任务实例在同一台机器上运行则只会出现一个 IP 子节点。可在 IP 地址节点写入
DISABLED 表示该任务实例禁用。
(五)sharding 节点
任务的分片信息,子节点是分片项序号,从 0 开始。分片个数是在任务配置中设置
的。分片项序号的子节点存储详细信息。每个分片项下的子节点用于控制和记录分片运
行状态。最主要的子节点就是 instance。
分片策略
一个task任务数据量十分大的时候,假如有10万条,如果是Quartz的话,一个任务只能在一个节点运行,那么这个节点就要运行10W条数据,可能要将近一天才能运行完这个10万条数据的任务.那么即使Quartz集群有五个节点,也只是一个节点在执行任务,剩下四个节点都在闲置着.
能不能给10万条数据拆分成5份,均匀的给五个节点去完成.这就是分片.
ShardingCount : 任务在触发的时候,有几个线程来执行这个任务.每一次触发任务的时候都会有四个线程去执行
1.分片策略
AverageAllocationJobShardingStrategy 的缺点是,一旦分片数小于作业服务器数,作业将永远分配至 IP 地址靠前的服务器,导致 IP 地址靠后的服务器空闲。而 OdevitySortByNameJobShardingStrategy 则可以根据作业名称重新分配服务器负载。如:
如果有 3 台服务器,分成 2 片,作业名称的哈希值为奇数,则每台服务器分到的分片是:1=[0], 2=[1], 3=[]
如果有 3 台服务器,分成 2 片,作业名称的哈希值为偶数,则每台服务器分到的分片是:3=[0], 2=[1], 1=[]
集群
部署两个相同代码的项目,只要连接的Zookeeper是一个数据源就行,观察控制台就能发现两个机器平均了分片,假如有4个分片,那么 A机器只运行 0 和1 分片 B机器只运行了 2和3 分片.