文章目录
一、目录结构
1.综述
Do;phinScheduler的server部分按照Maven项目的通常通常习惯划分为 main 和 test 两部分,main 中存放实际项目资源,test 存放测试项目资源,二者内部同时又划分为 source 和 resource 两部分,source 存放源代码,并按照习惯将该文件夹命名为 java,resource 存放资源配置文件。
2.src.main.java
该文件夹下仅有org.apache.dolphinscheduler.server这一个文件夹,该文件夹内分有builder、entity、log、master、monitor、registry、utils、worker这些文件夹,分别是server部分重要功能的核心代码。
3.test
如上所述,该部分是项目的测试部分,分为了java和resources两个文件夹。java文件夹便是对应原代码部分的测试,而resources文件夹仅有master.properties这一个配置文件。
值得注意的是这个文件中所有的内容均被注释掉了。仔细观察发现该文件中的内容均是对针对master类的配置,例如master.task.commit.interval=1000
master.task.commit.retryTimes=5
推测该配置是在测试master类时进行的相应设置,而根据代码细节可以推测master类的主要功能是掌控任务的提交和处理细节,例如上文的例子所表明的:任务提交的间隔时间、任务提交的最大重传次数等。
4.pom.xml
和大多数pom.xml一样,主要就是引入一些第三方库和工具类的依赖,定义dophinscheduler的版本号和组id(groupId)等。算是配置信息的一种。
二、对核心代码src.main.java的内容功能分析解读
1.org.apache.dolphinscheduler.server
1.builder
该文件夹下有且仅有TaskExecutionContextBuilder这一个java类。正如类名所揭示的那样,该类的主要功能是建立一个任务实例对象,并提供一些基本方法,用以访问或更改任务实例的属性值。
这个类下首先有get()方法返回当前任务实例对象,接着是该类的构造方法,然后是一个核心功能buildTaskInstanceRelatedInfo(TaskInstance taskInstance),返回TaskExecutionContextBuilder对象。
该方法设置任务执行对象的TaskInstanceId、TaskName、FirstSubmitTime等12项任务实例相关的重要属性,并进行严格包装,保证外部访问无法直接获取任务实例对象或其信息,而只能看到一个封装好的对象,从而保证了代码逻辑层上的封蔽性,提供了代码安全性的保障。
总结来说,builder类主要负责任务实例对象、进行中任务实例对象的实例化和信息封装,体现了java面向对象编程,属性分层封装的重要特点。
2.entity
该文件夹下有DataxTaskExecutionContext,DependenceTaskExecutionConte,ProcedureTaskExecutionContext,SQLTaskExecutionContext,SqoopTaskExecutionContext,TaskExecutionContext这六个类,分别提供了任务执行数据环境、任务执行依赖环境、任务执行流程环境、任务执行SQL环境、任务执行Sqoop环境、任务执行环境六个实体类对象属性和一些基本方法的定义。
具体来说,该类定义了相应实体属性名称和类型,并提供了基本的toString、get、set数据的方法。
3.log
开门见山地说,这个文件夹包含LoggerRequestProcessor、LoggerServer、MasterLogFilter、SensitiveDataConverter、TaskLogAppender(注:这个类在整个项目中从未引用过,其英文直译为附着器,推测可能是为了后续分布式系统下同时将日志输出到多个设备上,为了功能扩展所预留的类)、TaskLogDiscriminator、TaskLogFilter、WorkerLogFilter这几个类。
简而言之,这个文件夹主要负责日志的纪录和日志文件的保存与输出,具体细节我将放在接下来的文章中详细分析。
4.master
这个文件夹中代码量极为稠密,分类也细致入微,其重要性不言而喻。作为代码的核心部分我将会着重分析。依照惯例,具体的方法和内部逻辑将放在未来的几篇文章中。
分为 TaskInstanceCacheManager和 TaskInstanceCacheManagerImpl两个部分,其中impl意为implement,也就是实现,后者是对前者定义接口的具体实现。
这个类主要用于处理任务实例的缓存,在对一个任务实例进行某些可能造成不可恢复性破坏的关键操作前对其进行备份,扔进缓冲池,并记录下该实例的id等关键信息,设置一个定时器timer,标记当前实例的时间戳,以便在未来任务出错或超时时予以恢复。
这个类没什么好说的,就是进行一些基本配置,设定master监听的端口号等,以及提供一些基本方法来返回监听接口、当前任务状态、当前系统CPU使用情况等基本信息。
包含一个 TaskPriorityQueueConsumer类,该类继承自Thread,也就是说将会以线程的方式持续在后台运行。
该类按照任务的优先级依次取出任务扔给processor处理,并从缓冲池或任务等待队列中删除该任务。这蕴含了一个重要信息:dophinscheduler看待任务的模式是消费者-生产者模式,用这种简单而略显古老的处理模式提供对任务按优先级的分批次处理。

如图所示,该文件夹下的目录结构略显复杂,考虑到篇幅的问题我将会把细节部分暂时留到后面的几篇文章中进行详细的分析。
该类主要负责任务的分发。可以看到, context中定义了dispatch线程的运行环境,定义了主机Host和工作组workerGroup等信息,而 enums枚举了任务执行者的类别(其实只分了WORKER和CLIENT两种), executor主要包含执行核心功能的关键代码, host则处理主机信息,进一步分配工作。
可以看到,造成代码结构如此复杂的主要原因在于处理者身份和主机的复杂多变,而这也正指向该文件夹所揭示出的核心问题:dophinscheduler主要面向分布式系统,利用多处大量的低级计算资源进行汇总,以获得更为强大的计算能力,以此共同处理任务。所以,区分主机的繁琐与复杂正是本项目所不得不承的皇冠之重。
当然,DolphinScheduler也同样提供了基本的单机处理功能,满足个人用户的使用需求,也使得我们先前的配置与试用成为了可能。
分为 HostUpdateResponseProcessor(似乎没用到)、 StateEventProcessor、 TaskAckProcessor、 TaskKillResponseProcessor、 TaskResponseProcessor五种处理者进程,并维护了一个队列queue类,包含StateEventResponseService、TaskResponseEvent、TaskResponseService三个队列。
所有processor都有一个process方法,主要作用是打包一个事件对象,必要时记录日志,再调用addResponse方法。至于该方法的具体作用还需要后续深入研究代码才能给出结论。这里暂且按下不表。
registry即登记处,分为 MasterRegistryClient 、 MasterRegistryDataListener、 ServerNodeManager三个类,主要用于处理客户端的注册请求以及管理服务器节点。

用于线程调度。包括线程的生成、维护、销毁等。目录下还有task文件夹,细分了对针对任务设计的进程的线程启动类。
保存在master的根目录下一个java类。该类维护着主方法public static void main,其中调用了该类下实现的run和close方法。简而言之,这是主服务器的启动类。
至此,终于算是结束了对于master文件夹的分析。
5.monitor
该目录下包含monitor接口和一个具体的monitor实现类。比较有意思的是他命名为了抽象监视器AbstractMonitor来实现monitor接口,但他实际执行的却是确确实实的对服务器的监控和重启。不知“抽象”二字意义何在?
此外,MonitorServer类实际上继承的是CommandLineRunner类,并不是一个监听器而是整个监听器进程的启动进程。RegistryMonitorImpl作为RegistryMonitor的实现继承自AbstractMonitor,是对AbstractMonitor功能上的一种补充。RunConfig就是配置信息了没什么好说的。
6.registry
实际上先前master目录下所介绍的registry才是注册处的核心功能实现。这里只有一个HeartBeatTask类继承自Runnable类,事实上启动的是一个可以说是监听类——这里命名为心拍任务——用来检测并重启死去或者不在zookeeper中的用户注册处进程。
7.utils
工具类,定义了一些简单方法,引入了一部分第三方工具。
8.worker
来了,又是重头戏。
如此稠密的分析不仅是对笔者的极大的考验,相信对读者来说也是一种折磨。
该目录可以与master目录进行一个横向的对比。可以发现,这两个类的文件结构和命名,以及大体功能方法都比较相近。实际上,这正是在服务器中执行重要职责的两个角色:master和worker,管理者与工作者(主人与奴隶?)的核心代码。他们的工作,以及这每一个命名相似的类有很大程度上是一一对应的。
别忘了,DolphinScheduler最大的特点之一便是分布式,因此worker被master所分配的每一项工作都需要master进行相应的信息收集和处理,这样来看的话二者有着很高的结构相似度也就不足为奇了。
这里只有 ResponceCache,主要处理master的调度和响应,缓存master给予自己的命令及分配的任务的基本信息。
这里只有 WorkerConfig,配置类。
该类在master中不存在,为worker类独有。
继承自 AbstractDolphinPluginManager,有 addTaskChannelFactory、 loadTaskChannel、 installPlugin三个主要方法。其中第一个方法会在无异常的情况下调用第二个方法,实例化一个 taskChannelFactory对象并记录日志。第三个方法是对 DolphinSchedulerPlugin的重载,将生成的 TaskChannelFactory添加进当前worker,记录日志并记录进插件定义映射 pluginDefineMap。
有 DBTaskAckProcessor、 DBTaskResponseProcessor、 HostUpdateProcessor、 TaskCallbackService、 TaskExecuteProcessor、 TaskKillProcessor,分别负责数据库任务、数据库任务相应、主机交替、任务结果回传、任务执行和终止任务。
该文件夹大致结构与master.processor类同。
负责worker的注册登记,与master.registry类似。
线程启动类。有 RetryReportTaskStatusThread、 TaskExecuteThread、 WorkerManagerThread三个类,分别负责启动重启报告任务状态线程、任务执行线程、worker管理者线程。
与master类似,用于定义全局变量和启动、关闭、暂停主进程。额外有一个 initTaskPlugin方法负责初始化之前提到的任务插件。
附整体分析博客链接:
DolphinScheduler整体工作流程、工作逻辑及工作模块全面解析