分布式定时任务调度框架实践
1. 适用场景与痛点
1.1 定时任务适用场景
时间驱动处理
整点发送优惠券,每天更新收益,每天刷新标签数据和人群数据。
异步执行解耦
活动状态刷新,异步执行离线查询,与内部逻辑解耦。
批量处理数据
按月批量统计报表数据,批量更新短信状态,实时性要求不高。
1.2 业务需求和痛点
| 编号 | 需求/痛点 | 说明 |
|---|---|---|
| 01 | 任务执行监控告警能力 | 需要实时监控任务执行状态,异常时及时告警 |
| 02 | 任务可动态配置,无需重启 | 支持运行时动态调整任务配置,无需重启应用 |
| 03 | 业务透明,低耦合,开发方便 | 任务调度与业务逻辑解耦,降低开发复杂度 |
| 04 | 高可用,无单点故障 | 分布式部署,避免单点故障影响系统稳定性 |
| 05 | 任务不可重复执行,防止逻辑异常 | 确保任务在分布式环境下不重复执行 |
| 06 | 大任务的分发并行处理能力 | 支持大任务分片,并行处理提高执行效率 |
2. 开源框架探索
2.1 主流开源框架概览
| 框架 | 特点 | 适用场景 |
|---|---|---|
| Java 原生 | Timer 和 ScheduledExecutorService | 简单定时任务 |
| Spring Task | Spring 自主开发的轻量级定时任务框架,无需依赖其他包,配置简单 | 单机应用 |
| Quartz | Java 领域最著名的开源任务调度工具,开源定时任务框架几乎都是基于 Quartz 核心调度构建而成 | 企业级应用 |
| XXL-JOB | 轻量级分布式任务调度平台 - 易部署,开发迅速、学习简单、轻量级、易扩展 | 分布式系统 |
| Elastic-Job | 分布式调度解决方案,由两个相互独立的子项目 Elastic-Job-Lite 和 Elastic-Job-Cloud 组成 | 弹性调度场景 |
| PowerJob | 分布式任务调度与计算框架 -- 定时策略完善、工作流支持、高可用 & 高性能、故障转移与恢复 | 复杂任务场景 |
2.2 Java 原生方案
Timer
缺陷:
- 串行执行:前一个任务的延迟会影响到之后的任务的执行
- 异常传播:一旦某个定时任务在运行时产生未处理的异常,那么不仅当前这个线程会停止,所有的定时任务都会停止
- 依赖系统时间:任务执行是依赖于系统绝对时间,系统时间变化会导致执行计划的变更
ScheduledExecutorService
改进 VS 不足:
| 优势 | 不足 |
|---|---|
| 内部实现是 ScheduledThreadPool 线程池,可以支持多个任务并发执行 | 只能根据任务的延迟来进行调度 |
| 某一个线程执行的任务出现异常,也会影响处理,不会影响其他线程任务的执行 | 无法满足基于绝对时间和日历调度的需求 |
| 基于时间间隔的延迟,执行不会由于系统时间的改变发生变化 | - |
2.3 Spring Task
局限性:
Spring Task 本身不支持持久化,也没有推出官方的分布式集群模式,只能靠开发者在业务应用中自己手动扩展实现,无法满足可视化、易配置的需求。
3. 框架详解
3.1 Quartz
3.1.1 核心概念
| 概念 | 说明 |
|---|---|
| Job | 任务执行接口,只有一个 execute 方法,用于执行真正的业务逻辑 |
| JobDetail | 一个可执行的工作,用来描述 Job 实现类及其它相关的静态信息 |
| Trigger | 触发器,用于定义任务调度的时间规则,告诉任务调度器什么时候触发任务 |
| Calendar | 日历特定时间点的集合。一个 trigger 可以包含多个 Calendar |
| Scheduler | 任务调度器,是执行任务调度的控制器 |
| JobStore | 任务存储方式,主要有 RAMJobStore 和 JDBCJobStore |
3.1.2 调度时序图

3.1.3 执行时序图

3.1.4 缺陷与不足
| 问题 | 说明 |
|---|---|
| 性能影响 | 调度逻辑和执行逻辑并存于同一个项目中,在机器性能固定的情况下,业务和调度之间不可避免地会相互影响 |
| 高耦合 | 需要把任务信息持久化到业务数据表,和业务有耦合 |
| 伪负载均衡 | Quartz 集群模式下,是通过数据库独占锁来唯一获取任务,任务执行并没有实现完善的负载均衡机制 |
3.2 XXL-JOB
3.2.1 架构图

3.2.2 原理解析
通过将任务的调度控制和任务的执行解耦,业务使用只需要关注业务逻辑的开发。
3.2.3 可视化配置

3.3 ElasticJob
3.3.1 核心组成
ElasticJob 由两个相互独立的子项目组成:
- ElasticJob-Lite:轻量级无中心化解决方案
- ElasticJob-Cloud:采用自研 Mesos Framework 的解决方案,额外提供资源治理、应用分发以及进程隔离等功能
3.3.2 设计理念
通过弹性调度、资源管控、以及作业治理的功能,打造一个适用于互联网场景的分布式调度解决方案。
通过开放的架构设计,提供多元化的作业生态;各产品使用统一的作业 API,开发者仅需一次开发,即可随意部署。
3.3.3 核心功能
| 功能 | 说明 |
|---|---|
| 弹性调度 | 支持任务在分布式场景下的分片和高可用;能够水平扩展任务的吞吐量和执行效率;任务处理能力随资源配备弹性伸缩 |
| 资源分配 | 在适合的时间将资源分配给任务并使其生效;相同任务聚合至相同的执行器统一处理;动态调配追加资源至新分配的任务 |
| 作业治理 | 失效转移;错过作业重新执行;自诊断修复 |
| 作业依赖 (TODO) | 基于有向无环图(DAG)的作业间依赖;基于有向无环图(DAG)的作业分片间依赖 |
| 作业开放生态 | 可扩展的作业类型统一接口;丰富的作业类型库,如数据流、脚本、HTTP 等;易于对接业务作业,能够与 Spring 无缝整合 |
| 可视化管控端 | 作业管控端;作业执行历史数据追踪;注册中心管理 |
3.3.4 ElasticJob-Lite 架构

3.3.5 ElasticJob-Cloud

采用自研 Mesos Framework 的解决方案,额外提供资源治理、应用分发以及进程隔离等功能。
3.4 PowerJob
3.4.1 功能全景
| 功能 | 说明 |
|---|---|
| 任务调度 | Cron、固定频率、固定延迟、API |
| 工作流 | 任务编排、解决复杂任务依赖 |
| 在线运维 | 可视化前端页面轻松操作 |
| 动态容器 | 动态加载外部代码,灵活性 MAX |
| 分布式计算 | Map/MapReduce 计算方式支持 |
| 实时日志 | 日志白屏化,任务运行状态全知道 |
3.4.2 任务调度
| 特性 | 说明 |
|---|---|
| 调度策略 | 原生提供 CRON、固定频率、固定延迟三种最常见的调度策略 |
| 无锁设计 | 整个调度层采用无锁化设计,基于时间轮进行调度,低延迟,高性能! |
| 自定义 | 额外提供 OpenAPI 作为扩展调度策略,允许接入方完成调度层的自定义需求 |
3.4.3 工作流(DAG)
DAG:有向无环图
定义:在图论中,如果一个有向图无法从某个顶点出发经过若干条边回到该点,则这个图是一个有向无环图。
特点:
- 每个节点都是任务
- 支持上游任务结果传递
- 提供前端界面可视化
- 利用 DAG 轻松解决任务间复杂依赖问题

3.4.4 分布式计算
MapReduce 模型的创新实现
参考 @Alibaba SchedulerX 2.0 实现
3.4.5 动态容器
什么是动态容器?
PowerJob 的容器技术允许开发者开发独立于 worker 项目之外 Java 处理器,简单来说,就是以 Maven 工程项目的维度去组织一堆 Java 文件(众多任务处理器),进而兼具开发效率和可维护性。
特点:
- 使用简单!提供一键模版生成功能,真正的开箱即用
- 部署便捷!支持 Git 源码部署,一站式完成编译、打包、部署和加载
- 开发高效!动态容器支持完整 Spring 特性
使用场景?
比如有某个数据库数据订正任务,与主业务无关,写进原本的项目工程中不太优雅。这时候就可以单独创建一个用于数据操作的容器,在里面完成处理器的开发,通过 PowerJob 动态容器技术在 worker 集群上被加载执行。
3.4.6 实时日志 & 在线运维

3.4.7 系统组件

4. 产品对比与选型
4.1 产品对比

4.2 选型建议
对于并发场景不是特别高的系统来说:
xxl-job 配置部署简单易用,不需要引入多余的组件,同时提供了可视化的控制台,使用起来非常友好,是一个比较好的选择。
希望直接利用开源分布式框架能力的系统:
建议根据自身的情况来进行合适的选型。
5. 平台演示
5.1 演示环境



浙公网安备 33010602011771号