分布式任务调度框架:XXL-Job / ElasticJob / DolphinScheduler / SchedulerX 架构对比与选型

分布式任务调度框架:XXL-Job / ElasticJob / DolphinScheduler / SchedulerX 架构对比与选型

定时任务从单机走向分布式,"高可用、分片、防重复执行"是绕不开的三大难题。本文用一个统一的三阶段模型,把 XXL-Job、ElasticJob、DolphinScheduler、SchedulerX 四大主流框架的架构、差异和选型一次性讲清楚。


一、为什么需要分布式任务调度

在单体应用里,我们用 Timer、ScheduledExecutorService 或 Quartz 就能完成定时任务。但一旦进入分布式集群,同一个应用部署了多台机器,问题就来了:

  • 重复执行:每台机器上都有定时任务,到点后同一个任务被执行多次,导致数据重复、脏数据;
  • 单点故障:只在一台机器上跑,这台机器挂了,任务就彻底停摆;
  • 无法分片:一个任务要处理 100 万条数据,单机串行处理太慢,需要多台机器并行处理不同数据;
  • 运维困难:任务的启停、重跑、监控、告警都没有统一入口。

分布式任务调度框架就是为了解决这些问题而生。不同框架选择了不同的架构路线,主要分歧集中在三个问题上:

  1. 中心化 还是 去中心化?
  2. 服务端推送 还是 客户端自主?
  3. 调度与执行解耦 还是 合一?

下面我们逐个拆解。


二、四大框架架构详解

2.1 XXL-Job:中心式调度,轻量易用

XXL-Job 于 2015 年开源,核心设计目标是"开发迅速、学习简单、轻量级、易扩展",是目前国内中小团队使用最广泛的调度框架之一。

它采用调度与执行分离的架构,分为两部分:

  • 调度中心(admin):独立部署的 Web 服务,负责管理任务、按 cron 触发、路由、监控、告警;
  • 执行器(executor):业务应用引入 SDK,负责真正执行任务。

#mermaid-svg-pzR22GYMyh7m0fKk{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-pzR22GYMyh7m0fKk .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-pzR22GYMyh7m0fKk .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-pzR22GYMyh7m0fKk .error-icon{fill:#552222;}#mermaid-svg-pzR22GYMyh7m0fKk .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-pzR22GYMyh7m0fKk .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-pzR22GYMyh7m0fKk .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-pzR22GYMyh7m0fKk .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-pzR22GYMyh7m0fKk .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-pzR22GYMyh7m0fKk .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-pzR22GYMyh7m0fKk .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-pzR22GYMyh7m0fKk .marker{fill:#333333;stroke:#333333;}#mermaid-svg-pzR22GYMyh7m0fKk .marker.cross{stroke:#333333;}#mermaid-svg-pzR22GYMyh7m0fKk svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-pzR22GYMyh7m0fKk p{margin:0;}#mermaid-svg-pzR22GYMyh7m0fKk .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-pzR22GYMyh7m0fKk .cluster-label text{fill:#333;}#mermaid-svg-pzR22GYMyh7m0fKk .cluster-label span{color:#333;}#mermaid-svg-pzR22GYMyh7m0fKk .cluster-label span p{background-color:transparent;}#mermaid-svg-pzR22GYMyh7m0fKk .label text,#mermaid-svg-pzR22GYMyh7m0fKk span{fill:#333;color:#333;}#mermaid-svg-pzR22GYMyh7m0fKk .node rect,#mermaid-svg-pzR22GYMyh7m0fKk .node circle,#mermaid-svg-pzR22GYMyh7m0fKk .node ellipse,#mermaid-svg-pzR22GYMyh7m0fKk .node polygon,#mermaid-svg-pzR22GYMyh7m0fKk .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-pzR22GYMyh7m0fKk .rough-node .label text,#mermaid-svg-pzR22GYMyh7m0fKk .node .label text,#mermaid-svg-pzR22GYMyh7m0fKk .image-shape .label,#mermaid-svg-pzR22GYMyh7m0fKk .icon-shape .label{text-anchor:middle;}#mermaid-svg-pzR22GYMyh7m0fKk .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-pzR22GYMyh7m0fKk .rough-node .label,#mermaid-svg-pzR22GYMyh7m0fKk .node .label,#mermaid-svg-pzR22GYMyh7m0fKk .image-shape .label,#mermaid-svg-pzR22GYMyh7m0fKk .icon-shape .label{text-align:center;}#mermaid-svg-pzR22GYMyh7m0fKk .node.clickable{cursor:pointer;}#mermaid-svg-pzR22GYMyh7m0fKk .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-pzR22GYMyh7m0fKk .arrowheadPath{fill:#333333;}#mermaid-svg-pzR22GYMyh7m0fKk .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-pzR22GYMyh7m0fKk .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-pzR22GYMyh7m0fKk .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-pzR22GYMyh7m0fKk .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-pzR22GYMyh7m0fKk .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-pzR22GYMyh7m0fKk .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-pzR22GYMyh7m0fKk .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-pzR22GYMyh7m0fKk .cluster text{fill:#333;}#mermaid-svg-pzR22GYMyh7m0fKk .cluster span{color:#333;}#mermaid-svg-pzR22GYMyh7m0fKk div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-pzR22GYMyh7m0fKk .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-pzR22GYMyh7m0fKk rect.text{fill:none;stroke-width:0;}#mermaid-svg-pzR22GYMyh7m0fKk .icon-shape,#mermaid-svg-pzR22GYMyh7m0fKk .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-pzR22GYMyh7m0fKk .icon-shape p,#mermaid-svg-pzR22GYMyh7m0fKk .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-pzR22GYMyh7m0fKk .icon-shape .label rect,#mermaid-svg-pzR22GYMyh7m0fKk .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-pzR22GYMyh7m0fKk .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-pzR22GYMyh7m0fKk .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-pzR22GYMyh7m0fKk :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 执行器集群
调度中心集群
抢锁
抢锁
抢锁
调度中心-1
调度中心-2
调度中心-3
MySQL

schedule_lock 行锁
执行器-1
执行器-2
执行器-3

核心机制:数据库行锁保证单点触发

调度中心支持多节点部署做 HA,但调度前会执行:

sql 复制代码
SELECT * FROM xxl_job_lock WHERE lock_name = 'schedule_lock' FOR UPDATE;

这是 MySQL 行锁(独占锁),同一时刻只有一个调度中心节点能抢到锁、执行任务调度,其他节点阻塞等待。抢到锁的节点触发任务后,通过路由策略(轮询、随机、故障转移、分片广播等)选择一个执行器,下发任务。

优点:

  • 轻量级、开箱即用,一分钟上手;
  • 功能丰富:Web 可视化管理、GLUE 脚本在线编辑、日志查看、失败告警;
  • 调度中心与执行器解耦,执行器分布式 HA。

缺点:

  • 调度是单点串行的(虽然 HA),加调度中心节点只提升可用性,不提升调度吞吐;
  • 任务量大(万级、秒级)时,DB 锁竞争会带来明显调度延迟,数据库压力大;
  • 数据分片能力较弱(分片广播需要业务自己配合)。

2.2 ElasticJob:无中心,数据分片为特色

ElasticJob 最初由当当网开源,现在是 Apache ShardingSphere 的子项目 。它的定位是"轻量级无中心化解决方案 ",最大的特色是数据分片。

注意:ElasticJob 没有独立的调度中心,它是一个 jar 包,直接嵌入业务应用。业务应用本身就是"调度 + 执行"一体的节点,ZooKeeper 只负责协调。
#mermaid-svg-eXgzmNwdug9x5kiU{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-eXgzmNwdug9x5kiU .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-eXgzmNwdug9x5kiU .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-eXgzmNwdug9x5kiU .error-icon{fill:#552222;}#mermaid-svg-eXgzmNwdug9x5kiU .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-eXgzmNwdug9x5kiU .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-eXgzmNwdug9x5kiU .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-eXgzmNwdug9x5kiU .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-eXgzmNwdug9x5kiU .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-eXgzmNwdug9x5kiU .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-eXgzmNwdug9x5kiU .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-eXgzmNwdug9x5kiU .marker{fill:#333333;stroke:#333333;}#mermaid-svg-eXgzmNwdug9x5kiU .marker.cross{stroke:#333333;}#mermaid-svg-eXgzmNwdug9x5kiU svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-eXgzmNwdug9x5kiU p{margin:0;}#mermaid-svg-eXgzmNwdug9x5kiU .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-eXgzmNwdug9x5kiU .cluster-label text{fill:#333;}#mermaid-svg-eXgzmNwdug9x5kiU .cluster-label span{color:#333;}#mermaid-svg-eXgzmNwdug9x5kiU .cluster-label span p{background-color:transparent;}#mermaid-svg-eXgzmNwdug9x5kiU .label text,#mermaid-svg-eXgzmNwdug9x5kiU span{fill:#333;color:#333;}#mermaid-svg-eXgzmNwdug9x5kiU .node rect,#mermaid-svg-eXgzmNwdug9x5kiU .node circle,#mermaid-svg-eXgzmNwdug9x5kiU .node ellipse,#mermaid-svg-eXgzmNwdug9x5kiU .node polygon,#mermaid-svg-eXgzmNwdug9x5kiU .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-eXgzmNwdug9x5kiU .rough-node .label text,#mermaid-svg-eXgzmNwdug9x5kiU .node .label text,#mermaid-svg-eXgzmNwdug9x5kiU .image-shape .label,#mermaid-svg-eXgzmNwdug9x5kiU .icon-shape .label{text-anchor:middle;}#mermaid-svg-eXgzmNwdug9x5kiU .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-eXgzmNwdug9x5kiU .rough-node .label,#mermaid-svg-eXgzmNwdug9x5kiU .node .label,#mermaid-svg-eXgzmNwdug9x5kiU .image-shape .label,#mermaid-svg-eXgzmNwdug9x5kiU .icon-shape .label{text-align:center;}#mermaid-svg-eXgzmNwdug9x5kiU .node.clickable{cursor:pointer;}#mermaid-svg-eXgzmNwdug9x5kiU .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-eXgzmNwdug9x5kiU .arrowheadPath{fill:#333333;}#mermaid-svg-eXgzmNwdug9x5kiU .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-eXgzmNwdug9x5kiU .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-eXgzmNwdug9x5kiU .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-eXgzmNwdug9x5kiU .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-eXgzmNwdug9x5kiU .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-eXgzmNwdug9x5kiU .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-eXgzmNwdug9x5kiU .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-eXgzmNwdug9x5kiU .cluster text{fill:#333;}#mermaid-svg-eXgzmNwdug9x5kiU .cluster span{color:#333;}#mermaid-svg-eXgzmNwdug9x5kiU div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-eXgzmNwdug9x5kiU .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-eXgzmNwdug9x5kiU rect.text{fill:none;stroke-width:0;}#mermaid-svg-eXgzmNwdug9x5kiU .icon-shape,#mermaid-svg-eXgzmNwdug9x5kiU .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-eXgzmNwdug9x5kiU .icon-shape p,#mermaid-svg-eXgzmNwdug9x5kiU .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-eXgzmNwdug9x5kiU .icon-shape .label rect,#mermaid-svg-eXgzmNwdug9x5kiU .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-eXgzmNwdug9x5kiU .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-eXgzmNwdug9x5kiU .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-eXgzmNwdug9x5kiU :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 业务应用集群(内嵌 ElasticJob)
业务节点-1

分片项 0
业务节点-2

分片项 1
业务节点-3

分片项 2
ZooKeeper

注册 / 选主 / 分片协调

核心机制:数据分片(一个任务,多片并行)

ElasticJob 把一个任务 拆成 N 个分片项(sharding item,数字 0 到 N-1)。每个业务节点执行同一份代码,但通过 ShardingContext 拿到自己被分到的分片项,再用它过滤数据:

java 复制代码
public class MyJob implements SimpleJob {
    @Override
    public void execute(ShardingContext context) {
        int item = context.getShardingItem();        // 本节点的分片项:0/1/2
        int total = context.getShardingTotalCount(); // 分片总数:3
        // 只处理自己那一片:id % 3 == 分片项
        List<Data> list = query("SELECT * FROM t WHERE id % ? = ?", total, item);
        process(list);
    }
}

"主"是干什么的?

ElasticJob 会用 ZK 选举出一个 Leader(业务节点之一),但它不是全局主:

  • Leader 只负责在节点上下线、分片数变化时,做一次分片划分;
  • 定时触发不依赖它,每个节点本地都有定时(Quartz);
  • Leader 自己也执行任务,挂了就重新选举。

优点:

  • 无中心,无单点,节点对等;
  • 数据分片能力强,单个重任务可被多节点并行处理,节点增减时自动 re-sharding;
  • 支持弹性扩容、失效转移。

缺点:

  • 调度和执行都在业务进程内,对业务服务有资源和稳定性压力(重任务会拖慢同进程接口);
  • 没有独立的可视化管理 UI,运维能力弱;
  • 不支持工作流编排。

最佳实践:重任务不要和核心业务混部,把 ElasticJob 单独部署在专门的应用/机器上,既保留无中心分片,又实现进程隔离。


2.3 DolphinScheduler:去中心化多 Master,专注工作流

DolphinScheduler(简称 DS)是 Apache 顶级项目,定位是"分布式、易扩展的可视化 DAG 工作流编排平台",擅长复杂任务依赖和海量工作流调度。

它的核心服务包括:

  • Master:负责调度------切分 DAG、判断依赖、任务分片、监控状态、下发任务;
  • Worker:负责执行------本地跑脚本或远程调用,独立进程;
  • API:提供 RESTful 接口;
  • Alert:告警服务;
  • 注册中心:支持 ZooKeeper、Etcd、JDBC 多种实现。

#mermaid-svg-MnTakInIWK0HzXQl{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-MnTakInIWK0HzXQl .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MnTakInIWK0HzXQl .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MnTakInIWK0HzXQl .error-icon{fill:#552222;}#mermaid-svg-MnTakInIWK0HzXQl .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-MnTakInIWK0HzXQl .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MnTakInIWK0HzXQl .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MnTakInIWK0HzXQl .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MnTakInIWK0HzXQl .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MnTakInIWK0HzXQl .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MnTakInIWK0HzXQl .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MnTakInIWK0HzXQl .marker{fill:#333333;stroke:#333333;}#mermaid-svg-MnTakInIWK0HzXQl .marker.cross{stroke:#333333;}#mermaid-svg-MnTakInIWK0HzXQl svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-MnTakInIWK0HzXQl p{margin:0;}#mermaid-svg-MnTakInIWK0HzXQl .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-MnTakInIWK0HzXQl .cluster-label text{fill:#333;}#mermaid-svg-MnTakInIWK0HzXQl .cluster-label span{color:#333;}#mermaid-svg-MnTakInIWK0HzXQl .cluster-label span p{background-color:transparent;}#mermaid-svg-MnTakInIWK0HzXQl .label text,#mermaid-svg-MnTakInIWK0HzXQl span{fill:#333;color:#333;}#mermaid-svg-MnTakInIWK0HzXQl .node rect,#mermaid-svg-MnTakInIWK0HzXQl .node circle,#mermaid-svg-MnTakInIWK0HzXQl .node ellipse,#mermaid-svg-MnTakInIWK0HzXQl .node polygon,#mermaid-svg-MnTakInIWK0HzXQl .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-MnTakInIWK0HzXQl .rough-node .label text,#mermaid-svg-MnTakInIWK0HzXQl .node .label text,#mermaid-svg-MnTakInIWK0HzXQl .image-shape .label,#mermaid-svg-MnTakInIWK0HzXQl .icon-shape .label{text-anchor:middle;}#mermaid-svg-MnTakInIWK0HzXQl .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-MnTakInIWK0HzXQl .rough-node .label,#mermaid-svg-MnTakInIWK0HzXQl .node .label,#mermaid-svg-MnTakInIWK0HzXQl .image-shape .label,#mermaid-svg-MnTakInIWK0HzXQl .icon-shape .label{text-align:center;}#mermaid-svg-MnTakInIWK0HzXQl .node.clickable{cursor:pointer;}#mermaid-svg-MnTakInIWK0HzXQl .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-MnTakInIWK0HzXQl .arrowheadPath{fill:#333333;}#mermaid-svg-MnTakInIWK0HzXQl .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-MnTakInIWK0HzXQl .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-MnTakInIWK0HzXQl .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MnTakInIWK0HzXQl .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-MnTakInIWK0HzXQl .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MnTakInIWK0HzXQl .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-MnTakInIWK0HzXQl .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-MnTakInIWK0HzXQl .cluster text{fill:#333;}#mermaid-svg-MnTakInIWK0HzXQl .cluster span{color:#333;}#mermaid-svg-MnTakInIWK0HzXQl div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-MnTakInIWK0HzXQl .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-MnTakInIWK0HzXQl rect.text{fill:none;stroke-width:0;}#mermaid-svg-MnTakInIWK0HzXQl .icon-shape,#mermaid-svg-MnTakInIWK0HzXQl .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MnTakInIWK0HzXQl .icon-shape p,#mermaid-svg-MnTakInIWK0HzXQl .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-MnTakInIWK0HzXQl .icon-shape .label rect,#mermaid-svg-MnTakInIWK0HzXQl .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MnTakInIWK0HzXQl .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-MnTakInIWK0HzXQl .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-MnTakInIWK0HzXQl :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Worker 集群(独立进程)
Master 集群(去中心化)
Master-1

槽位 0
Master-2

槽位 1
Master-3

槽位 2
注册中心

ZK / Etcd / JDBC
Worker-1
Worker-2
Worker-3

核心机制:Command ID 取余分片

DS 对工作流产生的 Command 按 ID 取余分片,决定由哪个 Master 处理:

复制代码
槽位 = Command ID % Master 总数

例如 3 台 Master,Command ID 1001 → 1001 % 3 = 2,归槽位 2 的 Master 处理。所有 Master 同时工作,互不影响。

故障转移(failover)

某个 Master 挂掉后,它在注册中心的注册信息被移除,其他 Master 感知到后:

  1. 用分布式锁保证只有一个 Master 执行容错;
  2. 把挂掉 Master 的工作流实例 host 置为 null,创建 RECOVER_TOLERANCE_FAULT_PROCESS 类型的 Command;
  3. 其他 Master 捞到该 Command 后接管,遍历 DAG:已完成的节点保留,未完成的任务重新提交(重跑)。

单任务也能分片并行吗?

DS 没有"一个任务内部多片"的概念,但可以通过 DYNAMIC 动态节点实现:给一个集合(如 "0,1,2"),动态节点展开成多个并行子任务,每个子任务拿一个分片参数处理数据,最后汇合。

优点:

  • 调度层去中心化,多 Master 分片并行,加节点既 HA 又提升调度能力;
  • 工作流 DAG 可视化编排,擅长复杂依赖;
  • 调度与执行解耦,Worker 独立部署,故障隔离好;
  • 支持多租户、多任务类型、补数、重跑。

缺点:

  • 组件多(Master/Worker/API/Alert + 注册中心 + 数据库),部署和运维成本较高;
  • 轻量级场景下略显笨重。

2.4 SchedulerX:阿里云托管,企业级能力

SchedulerX 是阿里云商业化的分布式任务调度平台,同样采用去中心化、多 Server、无锁 架构。它可以理解为"XXL-Job 的内嵌执行端 + DS 的去中心化分片调度"的结合,并且服务端由阿里云托管、免运维。
#mermaid-svg-HXvpjOAmkspgXC9g{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-HXvpjOAmkspgXC9g .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-HXvpjOAmkspgXC9g .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-HXvpjOAmkspgXC9g .error-icon{fill:#552222;}#mermaid-svg-HXvpjOAmkspgXC9g .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-HXvpjOAmkspgXC9g .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-HXvpjOAmkspgXC9g .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-HXvpjOAmkspgXC9g .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-HXvpjOAmkspgXC9g .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-HXvpjOAmkspgXC9g .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-HXvpjOAmkspgXC9g .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-HXvpjOAmkspgXC9g .marker{fill:#333333;stroke:#333333;}#mermaid-svg-HXvpjOAmkspgXC9g .marker.cross{stroke:#333333;}#mermaid-svg-HXvpjOAmkspgXC9g svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-HXvpjOAmkspgXC9g p{margin:0;}#mermaid-svg-HXvpjOAmkspgXC9g .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-HXvpjOAmkspgXC9g .cluster-label text{fill:#333;}#mermaid-svg-HXvpjOAmkspgXC9g .cluster-label span{color:#333;}#mermaid-svg-HXvpjOAmkspgXC9g .cluster-label span p{background-color:transparent;}#mermaid-svg-HXvpjOAmkspgXC9g .label text,#mermaid-svg-HXvpjOAmkspgXC9g span{fill:#333;color:#333;}#mermaid-svg-HXvpjOAmkspgXC9g .node rect,#mermaid-svg-HXvpjOAmkspgXC9g .node circle,#mermaid-svg-HXvpjOAmkspgXC9g .node ellipse,#mermaid-svg-HXvpjOAmkspgXC9g .node polygon,#mermaid-svg-HXvpjOAmkspgXC9g .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-HXvpjOAmkspgXC9g .rough-node .label text,#mermaid-svg-HXvpjOAmkspgXC9g .node .label text,#mermaid-svg-HXvpjOAmkspgXC9g .image-shape .label,#mermaid-svg-HXvpjOAmkspgXC9g .icon-shape .label{text-anchor:middle;}#mermaid-svg-HXvpjOAmkspgXC9g .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-HXvpjOAmkspgXC9g .rough-node .label,#mermaid-svg-HXvpjOAmkspgXC9g .node .label,#mermaid-svg-HXvpjOAmkspgXC9g .image-shape .label,#mermaid-svg-HXvpjOAmkspgXC9g .icon-shape .label{text-align:center;}#mermaid-svg-HXvpjOAmkspgXC9g .node.clickable{cursor:pointer;}#mermaid-svg-HXvpjOAmkspgXC9g .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-HXvpjOAmkspgXC9g .arrowheadPath{fill:#333333;}#mermaid-svg-HXvpjOAmkspgXC9g .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-HXvpjOAmkspgXC9g .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-HXvpjOAmkspgXC9g .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HXvpjOAmkspgXC9g .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-HXvpjOAmkspgXC9g .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HXvpjOAmkspgXC9g .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-HXvpjOAmkspgXC9g .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-HXvpjOAmkspgXC9g .cluster text{fill:#333;}#mermaid-svg-HXvpjOAmkspgXC9g .cluster span{color:#333;}#mermaid-svg-HXvpjOAmkspgXC9g div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-HXvpjOAmkspgXC9g .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-HXvpjOAmkspgXC9g rect.text{fill:none;stroke-width:0;}#mermaid-svg-HXvpjOAmkspgXC9g .icon-shape,#mermaid-svg-HXvpjOAmkspgXC9g .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HXvpjOAmkspgXC9g .icon-shape p,#mermaid-svg-HXvpjOAmkspgXC9g .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-HXvpjOAmkspgXC9g .icon-shape .label rect,#mermaid-svg-HXvpjOAmkspgXC9g .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HXvpjOAmkspgXC9g .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-HXvpjOAmkspgXC9g .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-HXvpjOAmkspgXC9g :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 业务应用集群(内嵌 agent)
SchedulerX Server 集群(阿里云托管,多副本)
Server-1

调度任务 A 组
Server-2

调度任务 B 组
Server-3

调度任务 C 组
业务应用-1

agent
业务应用-2

agent
业务应用-3

agent

核心机制:多 Server 分片、无锁、水平扩展

  • 不同 Server 调度不同任务,无锁竞争,水平扩展,官方称支持百万级任务;
  • 多副本 + 数据三备份,可容忍任意两个节点故障或整个数据中心断电,经历阿里双十一验证;
  • 业务应用引入 agent(支持 Java/Go/Python/Shell/HTTP),Server 到点后主动调用 agent,agent 执行业务方法。

丰富的任务模型:

模型 说明 场景
单机 随机选一个 Worker 执行 普通定时任务
广播 Broadcast 所有 Worker 跑同一方法 缓存刷新、配置重载
分片(静态/动态) 多机分片处理 分库分表、分布式跑批
Map 根任务切块,分发多 Worker 并行 大数据集并行
MapReduce Map 分发 + 全部完成后 Reduce 聚合 轻量级分布式跑批
工作流 DAG 可视化拖拽编排 多任务依赖

优点:

  • 服务端免运维,开箱即用,企业级 SLA;
  • 多 Server 无锁分片,支持百万级、秒级调度;
  • 任务模型最全,一个平台覆盖分片、广播、MapReduce、工作流;
  • 兼容 XXL-Job、ElasticJob、Spring Schedule、K8s Job。

缺点:

  • 商业化产品,需要付费;
  • 绑定阿里云生态,不适合私有化/多云部署。

三、核心概念辨析

3.1 统一的三阶段模型

任何一次任务调度,都可以拆成三个阶段:
#mermaid-svg-qDcVvilanombE9LR{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-qDcVvilanombE9LR .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-qDcVvilanombE9LR .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-qDcVvilanombE9LR .error-icon{fill:#552222;}#mermaid-svg-qDcVvilanombE9LR .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-qDcVvilanombE9LR .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-qDcVvilanombE9LR .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-qDcVvilanombE9LR .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-qDcVvilanombE9LR .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-qDcVvilanombE9LR .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-qDcVvilanombE9LR .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-qDcVvilanombE9LR .marker{fill:#333333;stroke:#333333;}#mermaid-svg-qDcVvilanombE9LR .marker.cross{stroke:#333333;}#mermaid-svg-qDcVvilanombE9LR svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-qDcVvilanombE9LR p{margin:0;}#mermaid-svg-qDcVvilanombE9LR .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-qDcVvilanombE9LR .cluster-label text{fill:#333;}#mermaid-svg-qDcVvilanombE9LR .cluster-label span{color:#333;}#mermaid-svg-qDcVvilanombE9LR .cluster-label span p{background-color:transparent;}#mermaid-svg-qDcVvilanombE9LR .label text,#mermaid-svg-qDcVvilanombE9LR span{fill:#333;color:#333;}#mermaid-svg-qDcVvilanombE9LR .node rect,#mermaid-svg-qDcVvilanombE9LR .node circle,#mermaid-svg-qDcVvilanombE9LR .node ellipse,#mermaid-svg-qDcVvilanombE9LR .node polygon,#mermaid-svg-qDcVvilanombE9LR .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-qDcVvilanombE9LR .rough-node .label text,#mermaid-svg-qDcVvilanombE9LR .node .label text,#mermaid-svg-qDcVvilanombE9LR .image-shape .label,#mermaid-svg-qDcVvilanombE9LR .icon-shape .label{text-anchor:middle;}#mermaid-svg-qDcVvilanombE9LR .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-qDcVvilanombE9LR .rough-node .label,#mermaid-svg-qDcVvilanombE9LR .node .label,#mermaid-svg-qDcVvilanombE9LR .image-shape .label,#mermaid-svg-qDcVvilanombE9LR .icon-shape .label{text-align:center;}#mermaid-svg-qDcVvilanombE9LR .node.clickable{cursor:pointer;}#mermaid-svg-qDcVvilanombE9LR .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-qDcVvilanombE9LR .arrowheadPath{fill:#333333;}#mermaid-svg-qDcVvilanombE9LR .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-qDcVvilanombE9LR .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-qDcVvilanombE9LR .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-qDcVvilanombE9LR .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-qDcVvilanombE9LR .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-qDcVvilanombE9LR .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-qDcVvilanombE9LR .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-qDcVvilanombE9LR .cluster text{fill:#333;}#mermaid-svg-qDcVvilanombE9LR .cluster span{color:#333;}#mermaid-svg-qDcVvilanombE9LR div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-qDcVvilanombE9LR .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-qDcVvilanombE9LR rect.text{fill:none;stroke-width:0;}#mermaid-svg-qDcVvilanombE9LR .icon-shape,#mermaid-svg-qDcVvilanombE9LR .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-qDcVvilanombE9LR .icon-shape p,#mermaid-svg-qDcVvilanombE9LR .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-qDcVvilanombE9LR .icon-shape .label rect,#mermaid-svg-qDcVvilanombE9LR .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-qDcVvilanombE9LR .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-qDcVvilanombE9LR .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-qDcVvilanombE9LR :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} ① 调度判断

时间到没到
② 触发调用

发出请求/下发
③ 业务执行

真正跑逻辑

  • ① 调度判断:判断任务的触发时间是否到达;
  • ② 触发调用:发出请求、把任务下发到执行端;
  • ③ 业务执行:真正执行业务逻辑。

前两个阶段(①②)在调度端,第三个阶段(③)在执行端。

3.2 四个框架在三阶段的位置

框架 ① 调度判断 ② 触发调用 ③ 业务执行
XXL-Job 调度中心(DB 锁,一个做) 调度中心 执行器(业务应用)
ElasticJob 业务节点(本地 cron) 业务节点 业务节点
DolphinScheduler Master(分片) Master Worker(独立进程)
SchedulerX Server(分片) Server 业务端 agent

3.3 中心化 vs 去中心化

判断标准是"有没有一个统管全局的主":

  • 中心化:存在一个全局主,其他节点是它的从属。无论主是固定的还是选举出来的,都属于中心化。
  • 去中心化:没有全局主,多个节点对等分片。

注意:"自主选主"不等于"去中心化"。Raft、ZooKeeper 这类系统虽然能自主选主,但运行时仍然是单 Leader 主从结构,属于中心化的高可用(HA)。

3.4 推送 vs 自主

  • 服务端推送:调度端判断到点后,主动把任务下发给执行端。XXL-Job、DS、SchedulerX 都是推送模式。
  • 客户端自主:没有中心触发,节点本地定时、自己判断、自己执行。ElasticJob 是自主模式。

3.5 解耦 vs 合一

  • 调度与执行解耦:调度端和执行端分离,可独立扩展、故障隔离。XXL-Job、DS、SchedulerX 都是解耦的。
  • 调度与执行合一:调度和执行都在业务节点内。ElasticJob 是合一的。

四、四大框架横向对比

维度 XXL-Job ElasticJob DolphinScheduler SchedulerX
架构模式 中心式调度 无中心(内嵌) 去中心化多 Master 去中心化多 Server
调度与执行 分离 合一 分离 分离
调度层并行 单点(DB 锁) 节点本地 多 Master 分片 多 Server 分片,无锁
任务下发方式 推送 自主(本地) 推送 推送
数据分片 弱(分片广播) 强(数据分片) 动态节点实现 强(分片/Map/MapReduce)
工作流编排 弱 无 强 强
可视化管理 强 弱 强 强
执行端形态 内嵌业务应用 业务节点 独立 Worker 内嵌业务应用
部署方式 自建 自建 自建 云托管,免运维
规模上限 万级以下 中等 海量 百万级
成本 免费开源 免费开源 免费开源 商业付费

五、选型建议

场景 推荐框架 理由
任务量中小、想快速落地、团队小 XXL-Job 轻量、简单、开箱即用,社区成熟
单个任务数据量大、需要数据分片并行 ElasticJob 原生数据分片,无中心,弹性扩容
海量工作流、复杂 DAG 依赖、多租户 DolphinScheduler 去中心化多 Master,调度能力可水平扩展
企业级、规模大、要 SLA、在阿里云生态 SchedulerX 托管免运维,百万级,任务模型最全

选型时可以问自己三个问题:

  1. 任务规模多大?万级以下 XXL-Job 足够,万级以上考虑 DS / SchedulerX;
  2. 是"一堆独立任务"还是"一个任务要切数据"?后者优先 ElasticJob;
  3. 想自己运维还是接受云托管?要 SLA 且在云上 → SchedulerX。

六、总结

四大框架的架构差异,可以用四句话概括:

  • XXL-Job:中心式调度 + DB 锁单点触发,调度中心与执行器分离,胜在简单易用;
  • ElasticJob:无中心、jar 内嵌业务节点,本地定时 + 数据分片,胜在单任务并行;
  • DolphinScheduler:去中心化多 Master + 独立 Worker,分片调度 + 故障转移,胜在工作流编排;
  • SchedulerX:阿里云托管的去中心化多 Server,无锁分片 + 全任务模型,胜在企业级能力。
相关推荐
天远API1 小时前
零信任架构实战:基于天远风控经营异常预警构建自动化供应商店铺巡检网关
人工智能·架构·自动化·dubbo
AI行业应用研究1 小时前
会务信息载体的演进:纸质、PDF 与结构化数据源的分发成本与版本一致性
大数据·人工智能·安全·小程序·架构·pdf
明月无心照西山2 小时前
分布式任务系统的监控告警分级与自愈设计——以帮帮星球为例
分布式
guo_wen_qiang2 小时前
kafka一直restarting,报错InconsistentClusterIdException
分布式·kafka
JPower_mr.g2 小时前
SmartCall 音色管理技术解析:基于 SPI 的可扩展音色注册架构
java·开发语言·人工智能·ai·架构·开源
实战派K8S&DB2 小时前
TDSQL 核心模块与进程体系
运维·数据库·分布式·sql·mysql
我不是阵雨2 小时前
微服务幂等性深度解剖
微服务·云原生·架构
仍然.2 小时前
Redis---分布式锁
数据库·redis·分布式
七夜zippoe2 小时前
Agent 中间件架构:钩子链、插件注册与横切治理
ai·中间件·架构·agent·钩子链