背景概述在业务场景中,经常需要使用以下计划任务:
时间驱动场景:在某个时间点发送优惠券、发送邮件、取消未付订单等。 批量处理数据:批量汇总上个月的发票,或全部同步商品数据。 固定频率场景:必须每隔一定时间运行一次。 以往定时任务的实现方案,例如Timer、Quartz等存在或多或少的问题:
不支持集群的高可用性、监视、故障警报等。 不支持分布式任务调度,如没有统一的管理平台,不支持每个服务节点的任务调度汇总和跟踪结果。 如果同一服务的多个实例的任务具有互斥,则需要统一的调度。
ElasticJobelastic-job是当当网基于quartz二次开发后的分布式调度解决方案,是两个相对独立的子项目Elastic-Job-Lite和quartz
ElasticJob-Lite定位是一个非中心分布式调度框架,采用zookeeper实现分布式协调,实现任务的高可用性和分片。
ElasticJob-Cloud提供资源管理、APP应用程序分发和流程隔离等功能。
不支持无中心化elastic job-liteelasticjob-cloud资源分配吗? 不支持工作模式驻留瞬时部署。 zookeeperzookeepermesos 3358 www.Sina.com /
1 .工作开始
2 .工作的执行
实现原理
elasticjob没有中心化,通过ZooKeeper的选举机制选出了主服务器。 如果主服务器锁定,新的主服务器将重新选举。
因此,elasticjob具有很好的可扩展性和可用性,但使用和运输有一定的复杂性。
XXL-JOB xxl-job是一个集中式管理系统,系统主要通过MySQL管理定时任务信息,通过DB锁保证集群分布式调度的一致性。 虽然扩展执行器会增加数据库的压力,但实际上大多数公司的任务数并不多。
到了计时器任务的触发时间,将任务信息从db引入存储器,向任务执行机构发出触发请求。 该任务致动器可以是bean、groovy脚本、python脚本等,也可以是外部的http接口。
与开源的elastic-jo B- lite (以zookeeper为协调员的“无中心”体系结构)相比,这种中心管理系统重量轻、出手快、易于维护。
http://www.Sina.com/http://www.Sina.com /
负责日程信息的管理,按照日程结构发出日程要求,自身不负责业务代码。 调度系统与任务解除绑定,在提高系统可用性和稳定性的同时,调度系统的性能不再受限于任务模块
支持可视化、简单且动态的管理调度信息,包括创建、更新、删除任务、GLUE开发和任务警报,所有这些操作都实时启用,支持调度结果监视和运行日志,执行机构Failover缺点
接收调度请求并运行任务逻辑。 任务模块集中于任务的执行等操作,开发和维护更加简单高效
接收调度中心的运行请求、退出请求、日志请求等。
执行此步骤的任务执行机构将根据部署的调度中心地址自动注册到调度中心。 达到任务触发条件,调度中心发布任务。 执行器基于线程池执行任务,将执行结果放入内存队列,并将执行日志写入日志文件。 的回调线程消耗内存队列中的运行结果,并主动向调度中心报告。 当用户在调度中心查看任务日志时,调度中心向任务执行器请求,任务执行器读取任务日志文件并返回日志详细信息。
3358 www.Sina.com/2.1.0版及更早版本的核心调度模块都基于quartz框架,从2.1.0版开始开发自研调度组件,并提供quarttz
xxl_job_info表记录定时任务信息,trigger_next_time(long )字段表示下一次触发时的任务时间已更改或触发任务后的下一次触发时间
计划任务继续从数据库中读取计划时间表thread秒内要运行的任务,立即将其置于触发器/时间轮上等待触发器,并更新trigger_next_time
当前时间now查询数据库中trigger_next_time在now 5秒以内的任务(0)对达到now时间后的任务(距离now 5秒以上) :不直接跳过执行; trigger_next_time(1 (复位1 (针对达到now时间后的任务) now 5秒以内)启动线程运行触发逻辑; 如果任务的下次触发时间在5秒以内,则进入时间轮(MapInteger,ListInteger秒数(1-60 )=
gt; 任务id列表);重置trigger_next_time(2)对未到达now时间的任务: 直接放到时间轮内;重置trigger_next_time定时任务ringThread:时间轮实现到点触发任务
时间轮数据结构:Map<Integer, List<Integer>> key是秒数(1-60) ,value是任务id列表获取当前时间秒数,从时间轮内移出当前秒数前2个秒数(避免处理耗时太长,跨过刻度,向前校验一个刻度)的任务列表id,触发任务;如何避免集群中的多个服务器同时调度任务?
当xxl-job应用本身集群部署(实现高可用HA)时,通过mysql悲观锁实现分布式锁(for update语句)
setAutoCommit(false)关闭隐式自动提交事务,启动事务select lock for update(显式排他锁,其他事务无法进入&无法实现for update)读db任务信息 -> 拉任务到内存时间轮 -> 更新db任务信息commit提交事务,同时会释放for update的排他锁(悲观锁)任务执行器注册中心是如何实现的?
xxl-job添加执行器到任务调度中心有两种方式
(1)客户端执行器自动将名称和机器地址注册到任务调度中心,任务调度中心对外提供注册地址/api用来接受任务执行器注册的相关服务器信息
(2)在任务调度中心手动录入执行器名称和相关的机器地址,使用db表xxl_job_group记录下执行器的信息:执行器AppName、执行器名称title、执行器地址列表address_list(多地址逗号分隔)
如何实现任务执行器的路由?
执行器集群部署时提供丰富的路由策略,包括:第一个、最后一个、轮询、随机、一致性HASH、最不经常使用、最近最久未使用、故障转移、忙碌转移等;
第一个、最后一个、轮询、随机:都是简单读address_list即可一致性HASH:TreeSet实现一致性hash算法最不经常使用、最近最久未使用:HashMap、LinkedHashMap故障转移:遍历address_list获取address时,逐个检查该address的心跳(请求返回状态);只有心跳正常的address才返回使用忙碌转移:遍历address_list获取address时,逐个检查该address是否忙碌(请求返回状态);只有状态为idle的address才返回使用如何实现任务分片、并行执行? 拉出任务的执行机器列表,逐个设置index / total,把index / total分发到任务执行器任务执行器可根据index / total参数开发分片任务
问题 高频调度的执行时间比较长的任务
一般建议指定到单独一台主机上并保证在单机上任务不会并发执行来解决。
定时任务中依赖任务
1)任务依赖不支持环,只支持DAG;
如:A->B->(C,D)->E 其中CD并行,其余串行
2)下游任务只支持上游所有任务都成功并调度时间到了,才执行任务;
如:JobA只有在Job1,Job2,Job3都执行完,并且时间到了才能执行。
3)不支持有不同调度周期的任务存在依赖关系
如:A->B B的前置任务为A, A的调度周期为每15分钟调度一次, B为每天早上1点调度,该任务不建议分布式调度中心执行。
很难判断前置任务是成功还是失败;建议把A任务拆分为两个任务,一个为B对前置任务A1,一个为每15分钟执行一次(调度时间过滤掉A1)的任务
任务重复执行
JobA依赖Job1,Job2,Job3执行,同时JobA3点也会调度执行,在3点左右时,Job3执行完后会执行JobA,同时cron调度也会执行JobA,在这种情况怎么保证JobA只被执行一次。
解决办法:在JobA执行前需要把JobA的状态修改为正在执行中,此时,通过update where jobId = #{jobId} and status=#{未开始执行} 方法执行更新,如果更新记录为1的,任务可以进行执行,如果更新记录为0,抛弃该任务的执行。
怎么判断任务该不该执行
条件一:1点钟Job1执行完了,开始找后置任务JobA,JobA是否该执行?怎么判断?
JobA不该执行,前置任务Job2,Job3 都没开始执行,Job1不能执行;
条件二:3点钟Job3执行完了,开始找后置任务JobA,JobA是否该执行?怎么判断?
JobA不该执行,前置任务Job1,Job2,Job3 都执行完了,但是Cron时间还没到,Job1不能执行;
条件三:3点15分调度器开始调度,JobA是否该执行,怎么判断?
JobA该执行,前置任务Job1,Job2,Job3 都执行完了,Cron时间也到了;
判断任务是否执行的逻辑: 如果JobA执行时,需要判断Job1,Job2,Job3是否执行,下面拿Job1为例
假设Job1的历史任务都是正常执行成功的。
情况1: 2019-06-26 00:30:00(today)时,Job1的上一次执行成功时间为2019-06-25:01:00:00 (lastDay),下一次执行时间为:2019-06-26 01:00:00(nextDay).
情况2: 2019-06-26 01:30:00时,Job1的上一次执行成功时间为2019-06-26:01:00:00,下一次执行时间为:2019-06-27 01:00:00.
任务失败了怎么办?
任务失败应该同时执行带依赖执行和不带依赖执行,由页面配置控制。如果页面配置执行任务有参数,参数需要传递给依赖任务。
参考:
ElasticJob官网文档:http://shardingsphere.apache.org/elasticjob/
Elastic-job 介绍与使用:https://www.jianshu.com/p/4dc449cdeb67
LTS源码地址:https://github.com/ltsopensource/light-task-scheduler
sia-task源码地址:https://gitee.com/mirrors/sia-task?hmsr=aladdin1e6
XXL-JOB源码地址:https://github.com/xuxueli/xxl-job
3千字带你搞懂XXL-JOB任务调度平台:https://baijiahao.baidu.com/s?id=1681035278234207562&wfr=spider&for=pc
XXL-JOB(4) 原理分析:http://www.heartthinkdo.com/?p=3181
分布式任务调度系统xxl-job小结:https://zhuanlan.zhihu.com/p/91862341
xxl问题汇总:https://www.cnblogs.com/smileIce/p/11156412.html
xxl-job原理:https://blog.csdn.net/笨笨的犀牛/article/details/90701592