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


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

基本介绍

项目开发中,常常以下场景需要分布式任务调度:

  • 同一服务多个实例的任务存在互斥时,需要统一协调
  • 定时任务的执行需要支持高可用、监控运维、故障告警
  • 需要统一管理和追踪各个服务节点定时任务的运行情况,以及任务属性信息,例如任务所属服务、所属责任人

因此,XXL-JOB应运而生:
XXL-JOB是一个开源的轻量级分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展、开箱即用,其中“XXL”是主要作者,大众点评许雪里名字的缩写

自2015年开源以来,已接入数百家公司的线上产品线,接入场景涉及电商业务,O2O业务和大数据作业等

功能特性

主要功能特性如下:

  • 简单灵活
    提供Web页面对任务进行管理,管理系统支持用户管理、权限控制;
    支持容器部署;
    支持通过通用HTTP提供跨平台任务调度;

  • 丰富的任务管理功能
    支持页面对任务CRUD操作;
    支持在页面编写脚本任务、命令行任务、Java代码任务并执行;
    支持任务级联编排,父任务执行结束后触发子任务执行;
    支持设置任务优先级;
    支持设置指定任务执行节点路由策略,包括轮询、随机、广播、故障转移、忙碌转移等;
    支持Cron方式、任务依赖、调度中心API接口方式触发任务执行

  • 高性能
    调度中心基于线程池多线程触发调度任务,快任务、慢任务基于线程池隔离调度,提供系统性能和稳定性;
    任务调度流程全异步化设计实现,如异步调度、异步运行、异步回调等,有效对密集调度进行流量削峰;

  • 高可用
    任务调度中心、任务执行节点均 集群部署,支持动态扩展、故障转移
    支持任务配置路由故障转移策略,执行器节点不可用是自动转移到其他节点执行
    支持任务超时控制、失败重试配置
    支持任务处理阻塞策略:调度当任务执行节点忙碌时来不及执行任务的处理策略,包括:串行、抛弃、覆盖策略

  • 易于监控运维
    支持设置任务失败邮件告警,预留接口支持短信、钉钉告警;
    支持实时查看任务执行运行数据统计图表、任务进度监控数据、任务完整执行日志;

系统设计

1 设计思路

将调度行为抽象形成“调度中心”公共平台,而平台自身并不承担业务逻辑,“调度中心”负责发起调度请求;
将任务抽象成分散的JobHandler,交由“执行器”统一管理,“执行器”负责接收调度请求并执行对应的JobHandler中业务逻辑;
因此,“调度”和“任务”两部分可以相互解耦,提高系统整体稳定性和扩展性;

2 系统组成

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

  • 执行模块(执行器): 负责接收调度请求并执行任务逻辑。任务模块专注于任务的执行等操作,开发和维护更加简单和高效; 接收“调度中心”的执行请求、终止请求和日志请求等

功能架构

3 工作原理

XXL-JOB任务执行流程

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

4 HA设计

4.1 调度中心高可用

调度中心支持多节点部署,基于数据库行锁保证同时只有一个调度中心节点触发任务调度,参考com.xxl.job.admin.core.thread.JobScheduleHelper#start

Connection conn = XxlJobAdminConfig.getAdminConfig().getDataSource().getConnection();
connAutoCommit = conn.getAutoCommit();
conn.setAutoCommit(false);
preparedStatement = conn.prepareStatement(  "select * from xxl_job_lock where lock_name = 'schedule_lock' for update" );
preparedStatement.execute();

# 触发任务调度

# 事务提交
 conn.commit();

4.2 任务调度高可用

  • 路由策略
    调度中心基于路由策略路由选择一个执行器节点执行任务,XXL-JOB提供了如下路由策略保证任务调度高可用:

  • 忙碌转移策略*: 下发任务前向执行器节点发起rpc心跳请求查询是否忙碌,如果执行器节点返回忙碌则转移到其他执行器节点执行(参考 com.xxl.job.admin.core.route.strategy.ExecutorRouteBusyover)

  • 故障转移策略*: 下发任务前向执行器节点发起rpc心跳请求查询是否在线,如果执行器节点没返回或者返回不可用则转移到其他执行器节点执行 (参考com.xxl.job.admin.core.route.strategy.ExecutorRouteFailover)

  • 阻塞处理策略
    当执行器节点存在多个相同任务id的任务未执行完成,则需要基于阻塞策略对任务进行取舍:

  • 串行策略*:默认策略,任务进行排队、丢弃旧任务策略丢弃新任务策略
    (参考:com.xxl.job.core.biz.impl.ExecutorBizImpl#run)

同类框架比较

特性 quartz elastic-job-lite xxl-job LTS
依赖 MySQL、jdk jdk、zookeeper mysql、jdk jdk、zookeeper、maven
高可用 多节点部署,通过竞争数据库锁来保证只有一个节点执行任务 通过zookeeper的注册与发现,可以动态的添加服务器 基于竞争数据库锁保证只有一个节点执行任务,支持水平扩容。可以手动增加定时任务,启动和暂停任务,有监控 集群部署,可以动态的添加服务器。可以手动增加定时任务,启动和暂停任务。有监控
任务分片 ×
管理界面 ×
难易程度 简单 简单 简单 略复杂
高级功能 - 弹性扩容,多种作业模式,失效转移,运行状态收集,多线程处理数据,幂等性,容错处理,spring命名空间支持 弹性扩容,分片广播,故障转移,Rolling实时日志,GLUE(支持在线编辑代码,免发布),任务进度监控,任务依赖,数据加密,邮件报警,运行报表,国际化 支持spring,spring boot,业务日志记录器,SPI扩展支持,故障转移,节点监控,多样化任务执行结果支持,FailStore容错,动态扩容。
版本更新 半年没更新 2年没更新 最近有更新 1年没更新

使用

快速上手

具体如何快速上手使用,官方文档:http://www.xuxueli.com/xxl-job/ 已经介绍得比较详细和清楚,不再赘述

注意事项

  • 1 时钟同步问题
    调度中心和任务执行器需要时间同步,同步时间误差需要在3分钟内,否则抛出异常
    参考:com.xxl.rpc.remoting.provider.XxlRpcProviderFactory#invokeService

    if (System.currentTimeMillis() - xxlRpcRequest.getCreateMillisTime() > 3*60*1000) {
      xxlRpcResponse.setErrorMsg("The timestamp difference between admin and executor exceeds the limit.");
      return xxlRpcResponse;
    }
  • 2 时区问题
    任务由调度中心触发,按照在调度中心设置任务的cron表达式触发时,需要注意部署调度中心的机器所在的时区,按照该时区定制化cron表达式

  • 3 任务执行中服务宕掉问题
    调度中心完成任务下发,执行器在执行任务的过程中,如果执行器突然服务宕掉,会导致任务的执行问题在调度中心是执行中,调度中心并不会发起失败重试。即使任务设置了超时时间,执行器宕掉导致导致任务长时间未执行完成,调度中心界面也不会看到任务超时,因为任务超时是由执行器检测的并上报给调度中心的

因此遇到任务长时间未执行完成,可以关注是否发生了执行器突然服务宕掉

  • 4 优雅停机问题
    执行器执行任务基于线程池异步执行,当需要重启时需要注意线程池中还有未执行完成任务的问题,需要优雅停机,可以直接基于XxlJobExecutor.destroy()优雅停机,注意该方法在v2.0.2之前的版本存在bug导致无法优雅停机,v2.0.2及之后的版本才修复(参考:https://github.com/xuxueli/xxl-job/issues/727)

  • 5 失败重试问题
    当执行器节点部分服务不可用,例如节点磁盘损坏,但在调度中心仍然处于在线时,调度中心仍可能基于路由策略(包括故障转移策略)路由到该未下线的节点,并不断重试,不断失败,导致重试次数耗尽。所以路由策略尽量不要采用固定化策略,例如固定第一个、固定最后一个

总结

XXL-JOB上手还是比较简单,项目源码还是比较整洁,容易读懂,学习之后可以更加深入理解分布式系统设计、网络通信、多线程协同处理等知识点,推荐阅读​

参考

XXL-JOB github仓库
XXL-JOB 官方文档


 上一篇
架构设计方法初探 架构设计方法初探
作者 陈彩华 文章转载交流请联系 caison@aliyun.com最近学习了阿里资深技术专家李运华的架构设计教程,颇有收获,总结一下。 本文主要介绍架构设计的相关概念,系统复杂度的来源,架构设计的基本原则和流程。 1 基本概念和目的架构
2019-10-13
下一篇 
自研IM系统方案设计 自研IM系统方案设计
本文主要介绍APP功能中的IM模块的设计方案 1 设计原则 合适原则——合适优于业界领先 简单原则——简单优于复杂 演化原则——演化优于一步到位 架构设计的目的在于解决系统复杂度问题,真正优秀的架构都是企业当前人力、条件、业务等各种约束
2019-10-13
  目录