深入DolphinScheduler架构:Master-Worker分布式调度机制
本文详细解析了Apache DolphinScheduler的Master-Worker分布式调度架构。首先深入分析了Master Server的核心组件与职责,包括其模块化设计的网络通信层、任务调度层、状态管理层和注册中心层,以及MasterConfig配置管理、MasterSchedulerService调度服务、WorkflowExecuteThread工作流执行线程等关键组件。接着详细探讨了Worker Server的任务执行机制,包括任务接收与预处理、多级队列管理、任务插件化架构和容错机制。最后阐述了基于ZooKeeper的高可用集群架构和智能的任务队列与负载均衡策略,这些机制共同确保了系统在大规模分布式环境下的高可靠性和高性能。
Master Server核心组件与职责分析
Apache DolphinScheduler的Master Server是整个分布式调度系统的核心大脑,负责工作流的调度、任务分发、状态管理和故障恢复等关键功能。Master Server采用模块化设计,通过多个核心组件的协同工作,实现了高效、可靠的分布式任务调度能力。
核心组件架构
Master Server的核心组件架构采用分层设计,主要包括网络通信层、任务调度层、状态管理层和注册中心层:
核心组件详细分析
1. MasterConfig配置管理组件
MasterConfig是Master Server的配置管理中心,负责加载和管理所有运行时配置参数:
@Component
@PropertySource(value = "master.properties")
public class MasterConfig {
@Value("${master.listen.port:5678}")
private int listenPort; // 监听端口
@Value("${master.exec.threads:100}")
private int masterExecThreads; // 执行线程数
@Value("${master.exec.task.num:20}")
private int masterExecTaskNum; // 每个线程处理任务数
@Value("${master.dispatch.task.num:3}")
private int masterDispatchTaskNumber; // 分发任务数量
@Value("${master.host.selector:LowerWeight}")
private String hostSelector; // Worker选择策略
}
配置参数说明表:
| 配置项 | 默认值 | 说明 |
|---|---|---|
| master.listen.port | 5678 | Master Server监听端口 |
| master.exec.threads | 100 | 工作流执行线程池大小 |
| master.exec.task.num | 20 | 每个线程处理的任务实例数量 |
| master.dispatch.task.num | 3 | 每次分发给Worker的任务数量 |
| master.host.selector | LowerWeight | Worker主机选择策略 |
| master.heartbeat.interval | 10 | 心跳检测间隔(秒) |
| master.state.wheel.interval | 5 | 状态轮询间隔(秒) |
| master.failover.interval | 10 | 故障转移检测间隔(秒) |
2. MasterSchedulerService调度服务
MasterSchedulerService是核心调度服务,负责工作流实例的调度和执行:
public class MasterSchedulerService implements Runnable {
private ConcurrentHashMap<Integer, WorkflowExecuteThread> processInstanceExecMaps;
@Override
public synchronized void start() {
// 启动调度线程
this.schedulerThread = new Thread(this, "Master-Scheduler-Thread");
this.schedulerThread.start();
}
@Override
public void run() {
while (!Stopper.isStopped()) {
try {
// 从数据库获取待调度的工作流实例
List<ProcessInstance> processInstances =
processService.findProcessInstance4Scheduler();
for (ProcessInstance processInstance : processInstances) {
// 创建工作流执行线程
WorkflowExecuteThread workflowExecuteThread =
new WorkflowExecuteThread(processInstance, masterConfig);
// 提交到线程池执行
masterExecService.execute(workflowExecuteThread);
}
Thread.sleep(Constants.SLEEP_TIME_MILLIS);
} catch (Exception e) {
logger.error("Master scheduler thread error", e);
}
}
}
}
3. WorkflowExecuteThread工作流执行线程
WorkflowExecuteThread负责单个工作流实例的具体执行,包括任务解析、依赖关系处理和状态管理:
public class WorkflowExecuteThread implements Runnable {
private ProcessInstance processInstance;
private MasterConfig masterConfig;
@Override
public void run() {
try {
// 解析工作流DAG
ProcessDag processDag = generateFlowDag();
// 执行工作流任务
executeWorkflow(processDag);
// 处理任务状态更新
handleTaskStatusUpdate();
} catch (Exception e) {
logger.error("Execute workflow error", e);
}
}
private ProcessDag generateFlowDag() {
// 构建任务依赖关系图
return new ProcessDag(totalTaskNodeList, startNodeNameList,
recoveryNodeCodeList, depNodeType);
}
}
4. 网络通信处理器
Master Server通过多个Netty处理器与Worker节点进行通信:
| 处理器类 | 命令类型 | 职责描述 |
|---|---|---|
| TaskAckProcessor | TASK_EXECUTE_ACK | 处理任务执行确认 |
| TaskResponseProcessor | TASK_EXECUTE_RESPONSE | 处理任务执行结果 |
| TaskKillResponseProcessor | TASK_KILL_RESPONSE | 处理任务终止响应 |
| StateEventProcessor | STATE_EVENT_REQUEST | 处理状态事件请求 |
public class TaskResponseProcessor implements NettyRequestProcessor {
@Override
public void process(Channel channel, Command command) {
// 解析任务响应
TaskExecuteResponseCommand responseCommand =
(TaskExecuteResponseCommand) command;
// 更新任务状态
updateTaskStatus(responseCommand);
// 触发后续任务执行
triggerNextTasks(responseCommand.getTaskInstanceId());
}
}
5. MasterRegistryClient注册中心客户端
MasterRegistryClient负责与注册中心(ZooKeeper)的交互,实现服务发现和故障转移:
public class MasterRegistryClient {
public void start() {
// 注册Master节点
this.registry();
// 启动心跳检测
this.startHeartbeat();
// 监听Worker节点变化
this.watchWorkerNodes();
}
public void failoverMaster(String masterHost) {
// 执行Master故障转移
logger.info("Starting failover for master: {}", masterHost);
// 重新分配任务
reassignTasks(masterHost);
// 更新注册中心信息
updateRegistryInfo();
}
}
6. StateWheelExecuteThread状态轮询线程
StateWheelExecuteThread负责定时检查任务和工作流的状态,处理超时和重试逻辑:
public class StateWheelExecuteThread implements Runnable {
private Map<Integer, ProcessInstance> processTimeoutMap = new ConcurrentHashMap<>();
private Map<Integer, TaskInstance> taskTimeoutMap = new ConcurrentHashMap<>();
private Map<Integer, TaskInstance> taskRetryMap = new ConcurrentHashMap<>();
@Override
public void run() {
while (!Stopper.isStopped()) {
try {
// 检查任务超时
checkTask4Timeout();
// 检查任务重试
checkTask4Retry();
// 检查工作流超时
checkProcess4Timeout();
Thread.sleep(masterConfig.getStateWheelInterval() * 1000L);
} catch (Exception e) {
logger.error("State wheel thread error", e);
}
}
}
}
核心职责分析
工作流调度管理
Master Server负责解析工作流定义,构建任务依赖关系图(DAG),并按照依赖顺序调度任务执行。它维护着工作流实例的状态机,确保任务按照正确的顺序执行。
任务分发与负载均衡
通过HostManager组件,Master Server实现了多种Worker选择策略:
- LowerWeight:选择负载最低的Worker
- RoundRobin:轮询选择Worker
- Random:随机选择Worker
状态监控与故障恢复
Master Server通过心跳检测和状态轮询机制监控整个集群的健康状态。当检测到Worker节点故障时,会自动触发故障转移流程,将任务重新分配给健康的Worker节点。
资源管理
Master Server监控集群资源使用情况,包括CPU负载、内存使用等,确保任务分配到资源充足的Worker节点上执行,避免资源竞争和性能瓶颈。
Master Server的这些核心组件和职责共同构成了DolphinScheduler分布式调度系统的中枢神经系统,确保了大规模工作流调度的高效性、可靠性和可扩展性。
Worker Server任务执行机制详解
Apache DolphinScheduler的Worker Server是整个分布式调度系统的核心执行组件,负责接收Master Server分配的任务并在本地执行。Worker Server采用高度模块化的设计,通过多级队列管理、线程池调度、任务插件化等机制,实现了高效、可靠的任务执行能力。
任务接收与预处理机制
Worker Server通过Netty网络框架接收Master Server发送的任务执行请求。当TaskExecuteProcessor接收到TASK_EXECUTE_REQUEST命令时,会进行以下处理流程:
任务预处理阶段的关键步骤包括:
- 任务上下文解析:将接收到的JSON格式任务上下文转换为TaskExecutionContext对象
- 任务缓存:在TaskExecutionContextCacheManager中预缓存任务信息,确保极端情况下任务可追溯
- 资源检查:验证操作系统用户是否存在,必要时自动创建租户用户
- 响应通道建立:通过TaskCallbackService建立与Master的通信通道
任务调度与队列管理
Worker Server采用两级队列机制管理任务执行,确保系统在高负载下的稳定运行:
等待提交队列(DelayQueue)
// WorkerManagerThread中的队列定义
private final BlockingQueue<TaskExecuteThread> waitSubmitQueue;
private final ConcurrentHashMap<Integer, TaskExecuteThread> taskExecuteThreadMap;
// 任务提交逻辑
public boolean offer(TaskExecuteThread taskExecuteThread) {
if (waitSubmitQueue.size() > workerConfig.getWorkerExecThreads()) {
ThreadUtils.sleep(Constants.SLEEP_TIME_MILLIS);
if (waitSubmitQueue.size() > workerConfig.getWorkerExecThreads()) {
return false; // 队列已满,拒绝提交
}
}
return waitSubmitQueue.offer(taskExecuteThread);
}
线程池执行队列
WorkerExecService使用ListeningExecutorService管理任务执行线程池:
public class WorkerExecService {
private final ListeningExecutorService listeningExecutorService;
private final ConcurrentHashMap<Integer, TaskExecuteThread> taskExecuteThreadMap;
public void submit(TaskExecuteThread taskExecuteThread) {
taskExecuteThreadMap.put(taskExecuteThread.getTaskExecutionContext().getTaskInstanceId(), taskExecuteThread);
ListenableFuture future = this.listeningExecutorService.submit(taskExecuteThread);
Futures.addCallback(future, futureCallback, this.listeningExecutorService);
}
}
任务执行核心流程
TaskExecuteThread是任务执行的核心实现,其run()方法包含了完整的任务执行生命周期:
关键执行阶段详解
1. 环境准备阶段
// 创建本地执行目录
String execLocalPath = getExecLocalPath(taskExecutionContext);
FileUtils.createWorkDirIfAbsent(execLocalPath);
taskExecutionContext.setExecutePath(execLocalPath);
// 租户用户验证
if (!OSUtils.getUserList().contains(taskExecutionContext.getTenantCode())) {
throw new RuntimeException("tenantCode does not exist");
}
2. 资源下载阶段
// 下载HDFS/MinIO资源到本地
if (dryRun == Constants.DRY_RUN_FLAG_NO) {
downloadResource(taskExecutionContext.getExecutePath(),
taskExecutionContext.getResources(),
logger);
}
3. 任务插件执行阶段
// 通过插件管理器获取任务通道
TaskChannel taskChannel = taskPluginManager.getTaskChannelMap().get(taskExecutionContext.getTaskType());
TaskRequest taskRequest = JSONUtils.parseObject(JSONUtils.toJsonString(taskExecutionContext), TaskRequest.class);
// 创建具体任务实例并执行
task = taskChannel.createTask(taskRequest);
this.task.init(); // 任务初始化
this.task.handle(); // 任务执行
任务插件化架构
DolphinScheduler通过SPI(Service Provider Interface)机制实现了任务执行的插件化架构:
AbstractTask核心抽象类
public abstract class AbstractTask {
// 核心抽象方法
public abstract void handle() throws Exception;
public abstract AbstractParameters getParameters();
// 公共方法
public void init() { /* 默认实现 */ }
public ExecutionStatus getExitStatus() { /* 状态转换逻辑 */ }
}
任务执行器继承体系
任务状态管理与通信机制
状态响应处理
Worker Server通过TaskCallbackService与Master Server保持实时通信:
| 事件类型 | 命令类型 | 说明 |
|---|---|---|
| Event.ACK | TASK_EXECUTE_ACK | 任务开始执行确认 |
| Event.RESULT | TASK_EXECUTE_RESPONSE | 任务执行结果上报 |
| Event.KILL | TASK_KILL_RESPONSE | 任务终止响应 |
| Event.WORKER_REJECT | TASK_RECALL | Worker拒绝任务 |
响应缓存机制
ResponceCache确保在网络异常情况下消息不丢失:
public class ResponceCache {
private static final ConcurrentHashMap<Integer, Map<Event, Command>> CACHE = new ConcurrentHashMap<>();
public void cache(Integer taskInstanceId, Command command, Event event) {
Map<Event, Command> eventCommandMap = CACHE.computeIfAbsent(taskInstanceId, k -> new ConcurrentHashMap<>());
eventCommandMap.put(event, command);
}
}
资源管理与隔离机制
执行目录隔离
每个任务在独立的目录中执行,避免资源冲突:
execution/
├── project_{projectCode}/
│ ├── process_{processDefineCode}_{processDefineVersion}/
│ │ ├── instance_{processInstanceId}/
│ │ │ ├── task_{taskInstanceId}/
│ │ │ │ ├── scripts/ # 任务脚本
│ │ │ │ ├── resources/ # 依赖资源
│ │ │ │ ├── logs/ # 执行日志
│ │ │ │ └── tmp/ # 临时文件
租户资源隔离
通过操作系统用户实现多租户资源隔离:
// 租户用户检查与创建
if (CommonUtils.isSudoEnable() && workerConfig.getWorkerTenantAutoCreate()) {
OSUtils.createUserIfAbsent(taskExecutionContext.getTenantCode());
}
容错与故障恢复机制
任务重试机制
Worker Server支持任务级别的重试策略:
// 在任务执行异常时进行重试
try {
this.task.handle();
} catch (Throwable e)
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



