专栏首页chenchenchenXXL-JOB定时任务调度平台原理

XXL-JOB定时任务调度平台原理

背景概述

业务场景中经常有一些场景需要使用定时任务,比如:

  • 时间驱动的场景:某个时间点发送优惠券,发送短信,取消未支付订单等等。
  • 批量处理数据:批量统计上个月的账单,全量同步商品数据等等。
  • 固定频率的场景:每隔一定时间需要执行一次。

传统的定时任务实现方案,比如Timer,Quartz等都或多或少存在一些问题:

  • 不支持集群高可用,没有监控、故障告警等。
  • 没有统一管理平台,不支持统计和追踪各个服务节点任务调度的结果等
  • 不支持分布式任务调度:同一个服务多个实例的任务存在互斥时,需要统一的调度。

ElasticJob

elastic-job 是由当当网基于quartz 二次开发之后的分布式调度解决方案 , 由两个相对独立的子项目Elastic-Job-Lite和Elastic-Job-Cloud组成 。

ElasticJob-Lite定位是无中心化的分布式定时调度框架,采用zookeeper实现分布式协调,实现任务高可用以及分片。

ElasticJob-Cloud提供资源治理、应用分发以及进程隔离等功能。

ElasticJob-Lite

ElasticJob-Cloud

无中心化

资源分配

不支持

支持

作业模式

常驻

常驻 + 瞬时

部署依赖

ZooKeeper

ZooKeeper + Mesos

实现原理

1. 作业启动

2. 作业执行

缺点

elasticjob是无中心化的,通过ZooKeeper的选举机制选举出主服务器。如果主服务器挂了,会重新选举新的主服务器。

因此elasticjob具有良好的扩展性和可用性,但是使用和运维有一定的复杂。

XXL-JOB

xxl-job就是一个中心化管理系统,系统主要通过MySQL管理定时任务信息,通过DB锁保证集群分布式调度的一致性。虽然扩展执行器会增大DB的压力,但是实际上大部分公司任务数,执行器并不多。

当到了定时任务的触发时间,就把任务信息从db中拉进内存,对任务执行器发起触发请求。这个任务执行器,既可以是bean、groovy脚本、python脚本等,也可以是外部的http接口。

相比起当当网开源的elastic-job-lite(基于zookeeper作为协调器的“无中心”架构),这种中心化管理的系统轻量级、上手快、易于维护。

架构图

  • 调度模块(调度中心): 负责管理调度信息,按照调度配置发出调度请求,自身不承担业务代码。调度系统与任务解耦,提高了系统可用性和稳定性,同时调度系统性能不再受限于任务模块; 支持可视化、简单且动态的管理调度信息,包括任务新建,更新,删除,GLUE开发和任务报警等,所有上述操作都会实时生效,同时支持监控调度结果以及执行日志,支持执行器Failover。
  • 执行模块(执行器): 负责接收调度请求并执行任务逻辑。任务模块专注于任务的执行等操作,开发和维护更加简单和高效; 接收“调度中心”的执行请求、终止请求和日志请求等。

执行步骤

  • 任务执行器根据配置的调度中心的地址,自动注册到调度中心。
  • 达到任务触发条件,调度中心下发任务。
  • 执行器基于线程池执行任务,并把执行结果放入内存队列中、把执行日志写入日志文件中。
  • 执行器的回调线程消费内存队列中的执行结果,主动上报给调度中心。
  • 当用户在调度中心查看任务日志,调度中心请求任务执行器,任务执行器读取任务日志文件并返回日志详情。

定时触发任务是如何实现的?:使用时间轮实现

2.1.0版本前核心调度模块都是基于quartz框架,2.1.0版本开始自研调度组件,移除quartz依赖 ,使用时间轮调度。

  • xxl_job_info表记录定时任务信息,trigger_next_time(Long)字段记录下一次触发的时间点
  • 任务时间被修改 或者任务触发后,计算下一次触发时间戳并更新trigger_next_time字段

定时执行任务逻辑:

定时任务scheduleThread:不断从db把5秒内要执行的任务读出,立即触发 / 放到时间轮等待触发,并更新trigger_next_time

  • 获取当前时间now
  • 查询数据库中trigger_next_time在距now 5秒内的任务
  • (0)对到达now时间后的任务(超出now 5秒外):
    • 直接跳过不执行;
    • 重置trigger_next_time
  • (1)对到达now时间后的任务(超出now 5秒内):
    • 开线程执行触发逻辑;
    • 若任务下一次触发时间是在5秒内,则放到时间轮内(Map<Integer, List<Integer>> 秒数(1-60) => 任务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/yanghuangsanguo/article/details/90701592

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 任务调度-分布式任务调度平台XXL-JOB

    如果上述二种方式都不满足你的需求,我建议你尝试使用XXL-JOB或其他开源调度平台。

    秋日芒草
  • 分布式任务调度平台XXL-JOB

    XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。

    用户1518699
  • 分布式任务调度平台XXL-JOB

    任务调度是指基于给定的时间点,给定的时间间隔又或者给定执行次数自动的执行任务。我们可以思考一下在以下场景中,我们应该怎么实现:

    我没有三颗心脏
  • 【进阶之路】定时任务调用平台xxl-job

    .markdown-body{word-break:break-word;line-height:1.75;font-weight:400;font-size:...

    南橘
  • 转载《分布式任务调度平台XXL-JOB》

    XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。

    用户1518699
  • 分布式任务调度平台 → XXL-JOB 初探

    相信大家对任务调度都不陌生,说的通熟一点就是定时任务;这个在我们的项目中或多或少都存在,我们可以用 JDK 自带的(Timer、ScheduledExecuto...

    青石路
  • 分布式任务调度平台 → XXL-JOB 实战

      老师:谁知道鞭炮用英语怎么说?   甲:老师!老师!我知道,鞭炮的英文是pilipala。   老师:那闪电呢?   乙:kucha kucha   老师:...

    青石路
  • 分布式任务调度平台 XXL-JOB 2.0.0 发布

    XXL-JOB是一个轻量级分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。

    Debian中国
  • 基于XXL-JOB二次开发的分布式定时任务调度平台

    XXL-JOB是一个代码开源的分布式定时任务调度平台。XXL-JOB支持多种模式执行定时任务,如直接执行任务脚本代码、通过commandJobHandler调用...

    Java艺术
  • 搭建分布式任务调度平台

    3. 分布式任务调度中心会根据相应的路由策略选出其中的一个或者多个,然后再本地执行定时任务

    envoke
  • 笑话:大厂都在用的任务调度框架我能不知道吗???

    我之前的工作中一直在用 Elastic-Job 来做任务调度。这也是大家为什么能在我的书籍《Spring Cloud 微服务 入门 实战与进阶》中看到 Elas...

    猿天地
  • 分布式任务调度平台XXL-JOB搭建教程

      关于分布式任务调度平台XXL-JOB,其实作者 许雪里 在其发布的中文教程中已经介绍的很清楚了,这里我就不做过多的介绍了,关于其搭建教程,本人依照其文档搭建...

    IT可乐
  • 三千字带你搞懂XXL-JOB任务调度平台

    所以定时任务在平时开发中并不少见,而且对于现在快速消费的时代,每天都需要发送各种推送,消息都需要依赖定时任务去完成,应用非常广泛。

    java技术爱好者
  • 一文读懂分布式任务调度平台XXL-JOB

    本文主要介绍分布式任务调度平台XXL-JOB(v2.1.0版本),包括功能特性、实现原理、优缺点、同类框架比较等

    用户5397975
  • 后端技术:Java定时任务的五种创建方式

    job任务名:@JobHandler注解值 >> 如:@JobHandler(value=“demoJobHandler”)

    IT技术分享社区
  • 从官方文档到0day挖掘思路

    一些开源项目的官方文档我们可以挖掘到很多有用信息,比如API利用、默认口令、硬编码等。

    黑白天安全
  • Java任务调度框架之分布式调度框架XXL-Job介绍

    Java开发中经常会使用到定时任务:比如每月1号凌晨生成上个月的账单、比如每天凌晨1点对上一天的数据进行对账操作,在比如每天凌晨5点给180天未登陆过的用户发送...

    凯哥Java
  • 分布式任务调度平台XXL-JOB,不了解一下?

    任务调度是指基于给定的时间点,给定的时间间隔又或者给定执行次数自动的执行任务。我们可以思考一下在以下场景中,我们应该怎么实现:

    Bug开发工程师
  • 分布式任务调度的解决方案

    随着系统规模的发展,定时任务数量日益增多,任务也变得越来越复杂,尤其是在分布式环境下,存在多个业务系统,每个业务系统都有定时任务的需求,如果都在自身系...

    慕容千语

扫码关注云+社区

领取腾讯云代金券