
1. 从零开始为什么需要一个分布式工作流调度系统如果你负责过数据仓库的日常维护或者参与过需要定时跑批的业务系统开发那你一定对“调度”这件事不陌生。凌晨一点你设置的定时任务Cron Job准时启动从数据库拉取数据经过一系列清洗、转换最终生成报表。听起来很美好对吧但现实往往骨感任务A依赖任务B的输出B却因为上游数据延迟而失败某个任务运行时间远超预期挤占了后续任务的资源一个脚本的改动导致整个任务链在半夜集体崩溃而你只能在睡梦中被报警电话叫醒。这就是传统脚本定时器模式的典型困境。它们缺乏可视化的依赖管理、统一的失败重试机制、精细的资源控制和实时的任务监控。当任务数量从十几个增长到上百个依赖关系从线性变成复杂的网状结构时靠人力去维护和排查几乎是一场灾难。DolphinScheduler海豚调度就是为了解决这些问题而生的。它是一个开源的分布式可视化工作流任务调度平台你可以把它理解为一个功能强大的“任务编排与自动化指挥中心”。它的核心价值在于将你散落在各台服务器上的脚本、程序、SQL语句通过拖拽的方式组织成一张清晰的工作流图。在这张图上你可以直观地设置任务间的依赖关系、失败重试策略、超时告警并且由平台来保证整个流程按照你设定的逻辑可靠、高效地执行。最近社区里关于“dolphinscheduler改造后构建打包”的讨论很热这恰恰说明了它的另一个特点开放与可定制。很多团队会根据自身的技术栈比如特定的权限体系、文件存储系统对DolphinScheduler进行二次开发然后重新打包部署使其更贴合内部环境。这从侧面印证了它已不仅仅是一个“开箱即用”的工具更成为了许多企业数据平台底层的关键基础设施。所以无论你是想告别混乱的Crontab构建一个可靠的数据处理流水线还是为团队引入一个标准的任务调度中台DolphinScheduler都是一个非常值得投入时间学习的选项。接下来的内容我会以一个数据开发新手的视角带你完成从环境搭建到第一个工作流上线的全过程并分享那些官方文档里不会细说的实操细节和避坑点。2. 环境准备选对部署方式是成功的第一步在真正动手之前我们需要先把DolphinScheduler跑起来。官方提供了多种部署方式从单机快速体验到分布式生产集群。对于入门学习我强烈建议从Standalone单机模式开始。它把所有核心服务Master Server, Worker Server, API Server, Alert Server等打包在一个进程里一键启动非常适合本地开发和功能验证。别一上来就折腾集群那会极大增加你的学习成本容易在环境问题上耗尽热情。2.1 基础环境检查与配置DolphinScheduler的后端是Java写的前端是React数据存储依赖数据库。所以你的机器需要满足以下条件Java 8这是必须的。建议安装 OpenJDK 8 或 11这是经过广泛验证的稳定版本。用java -version命令检查。数据库MySQL (5.7) 或 PostgreSQL (8.2.15)。我以MySQL 8.0为例因为它更常见。你需要提前安装好MySQL并创建一个新的数据库比如叫dolphinscheduler。ZooKeeper (3.4.6)即使是Standalone模式DolphinScheduler也依赖ZooKeeper进行服务注册和分布式锁。你需要单独安装并启动一个ZooKeeper服务。对于本地测试单机ZooKeeper就足够了。操作系统Linux 或 macOS。生产环境肯定是Linux但如果你用macOS开发Standalone模式也能完美运行。这里有一个关键的避坑点版本兼容性。请务必去DolphinScheduler的 GitHub Release页面 下载最新的稳定版本比如本文撰写时的3.2.0。不要随便用master分支的代码也不要用太老的版本否则你可能遇到各种奇怪的依赖冲突或界面BUG。下载后你会得到一个类似apache-dolphinscheduler-3.2.0-bin.tar.gz的压缩包。解压它我们接下来的操作都在这个目录下进行。2.2 关键配置文件修改详解解压后进入conf目录。这里文件很多但入门阶段我们只需关注两个common.properties和datasource.properties。配置文件里的每一个项都值得仔细推敲理解它们能帮你避免很多运行时错误。首先编辑datasource.properties配置数据库连接。找到MySQL的配置部分# 数据源类型不改 spring.datasource.driver-class-namecom.mysql.cj.jdbc.Driver # 你的数据库连接地址注意时区设置很重要 spring.datasource.urljdbc:mysql://localhost:3306/dolphinscheduler?useUnicodetruecharacterEncodingUTF-8useSSLfalseserverTimezoneAsia/Shanghai # 连接数据库的用户名 spring.datasource.usernameroot # 连接数据库的密码 spring.datasource.passwordyour_password_here注意serverTimezoneAsia/Shanghai这个参数极其重要。如果不设置或者设置为其他值可能会导致任务执行时间记录错误、定时调度不准等诡异问题。请根据你所在时区调整。接着编辑common.properties。这个文件配置了系统的核心行为。# 资源存储的根路径。工作流中上传的脚本、资源文件都会放在这里。 resource.storage.typeHDFS resource.upload.path/tmp/dolphinscheduler # 对于Standalone模式我们先使用本地文件系统更简单。 resource.storage.typeLOCAL resource.upload.path/tmp/dolphinscheduler # 工作流执行时产生的日志存放路径。 dolphinscheduler.env.path/tmp/dolphinscheduler/logs # 是否开启邮件报警入门可以先关掉。 alert.typeemail mail.protocolsmtp mail.server.hostsmtp.163.com mail.server.port25 mail.senderyour_email163.com mail.useryour_email163.com mail.passwdyour_password mail.smtp.starttls.enabletrue mail.smtp.ssl.enablefalse mail.smtp.authtrue # 可以先设置为 false startup.alert.enablefalse这里我建议初学者先将resource.storage.type设置为LOCAL并将路径指向一个你有读写权限的目录比如/tmp/dolphinscheduler。这样可以避免一开始就去配置复杂的HDFS或S3。同样邮件报警也先关闭减少复杂度。2.3 初始化数据库与启动服务配置好文件后我们需要初始化数据库结构。DolphinScheduler提供了SQL脚本。进入解压目录的sql文件夹找到对应你数据库的脚本例如dolphinscheduler_mysql.sql。在你的MySQL客户端中连接到之前创建的dolphinscheduler数据库然后执行这个SQL文件。mysql -uroot -p dolphinscheduler /path/to/your/dolphinscheduler/sql/dolphinscheduler_mysql.sql执行成功后数据库里会创建几十张表这是平台运行的基础。现在激动人心的时刻到了启动服务。对于Standalone模式启动非常简单。在解压目录的根路径下执行bash ./bin/dolphinscheduler-daemon.sh start standalone-server你可以通过查看日志来确认启动是否成功tail -f logs/dolphinscheduler-standalone.log当你看到类似 “[INFO] 2024-05-XX XX:XX:XX.XXX org.apache.dolphinscheduler.server.standalone.StandaloneServer: [75] - Standalone server started” 的日志时说明服务已经启动成功。最后打开浏览器访问http://localhost:12345/dolphinscheduler。默认的用户名和密码是admin/dolphinscheduler123。首次登录会强制要求修改密码请务必牢记新密码。3. 核心概念扫盲项目、工作流与任务登录系统后你可能会对界面上的各种术语感到困惑。别急在动手创建之前我们必须先理解DolphinScheduler的几个核心概念这是正确使用它的基石。它们之间存在清晰的层级关系项目 工作流定义 工作流实例 任务实例。3.1 项目你的工作空间“项目”是最高层级的隔离单位。你可以把它理解为为一个特定的业务线或数据域创建的一个独立工作空间。例如你可以创建“用户画像数据项目”、“财务报表项目”、“风控模型训练项目”。不同项目之间的资源工作流、任务、文件默认是相互隔离的这有利于权限管理和职责划分。作为管理员你首先需要创建一个项目。3.2 工作流定义你的流程图蓝图在项目内部你创建的是“工作流定义”。这是一个静态的模板或蓝图。你在这里通过拖拽任务节点、连线设置依赖设计出整个数据处理流程的步骤图。这个定义本身不会自动运行它只是描述了“该怎么做”。一个工作流定义可以包含几十个甚至上百个任务节点。3.3 工作流实例与任务实例蓝图的一次具体执行当你手动点击“运行”或到达定时时间系统会根据“工作流定义”生成一个“工作流实例”。这是蓝图的一次具体执行。这次执行有唯一的ID、开始时间、结束时间和状态成功、失败、运行中。同样工作流中的每个任务节点也会生成对应的“任务实例”。你可以查看每次实例执行的详细日志这对于排查问题至关重要。理解定义和实例的区别是高效使用调度系统的关键。修改工作流定义不会影响已经生成的实例而查看历史运行情况你需要去实例页面而不是定义页面。3.4 任务类型你的工具箱DolphinScheduler支持丰富的任务类型这是它功能强大的体现。对于入门你需要先熟悉这几种Shell执行Shell脚本。最常用可以调用任何命令行工具。SQL直接执行一段SQL语句支持MySQL、PostgreSQL、Hive、Spark SQL等。它会自动去你配置的数据源中执行。子工作流调用另一个已存在的工作流定义。用于流程复用和模块化。条件分支根据上游任务的输出状态或自定义条件决定下游执行哪条路径。依赖检查指定的外部依赖如某个HDFS文件是否存在是否满足满足后才继续执行。其他如Python、Spark、Flink、MapReduce、DataX等任务类型则在处理更专业的计算引擎时使用。4. 第一个工作流实战构建一个简单的数据清洗流程现在我们动手创建一个真实的工作流。假设我们有一个简单的需求每天凌晨先检查某个数据文件是否就绪然后执行一个Shell脚本清洗数据清洗成功后再运行一段SQL将结果写入汇总表。4.1 创建项目与数据源首先用admin账号登录在首页点击“项目管理”创建一个新项目比如叫“Learning_Project”。创建成功后进入该项目。在开始画流程图之前我们需要先配置“数据源”。这样后续的SQL任务才知道去哪里执行。在项目首页找到“数据源中心”菜单。点击“创建数据源”选择MySQL。填写你的数据库连接信息主机、端口、库名、用户、密码并点击“测试连接”。看到“连接成功”的提示后再保存。这个数据源会在创建SQL任务时被用到。4.2 拖拽画布设计工作流DAG进入“工作流定义”菜单点击“创建工作流”。你会进入一个可视化的拖拽画布界面。添加“依赖”任务从左侧任务列表拖动一个“DEPENDENT”依赖节点到画布。双击节点进行编辑。任务名称可以改为“Check_File_Ready”。在“依赖条件”设置里我们可以添加一个“文件依赖”假设我们依赖HDFS上的一个文件/data/input/ready.flag。如果这个文件不存在任务就会等待或失败可配置。这里为了演示我们也可以先简单跳过详细设置。添加“Shell”任务拖动一个“SHELL”节点到画布放在“依赖”节点下方。用鼠标从“依赖”节点拖出一条线连接到“Shell”节点。这表示只有“Check_File_Ready”任务成功后“Shell”任务才会开始。双击Shell节点在脚本框里写入一个简单的命令比如echo “Starting data cleaning...“ sleep 5 echo “Cleaning finished.“。这个任务模拟了一个运行5秒的数据清洗脚本。添加“SQL”任务再拖动一个“SQL”节点到画布连接到“Shell”节点之后。编辑SQL任务在“数据源”下拉框中选择你刚才创建的MySQL数据源。在SQL脚本区域写一段简单的语句例如INSERT INTO test_summary (exec_date, result) VALUES (CURDATE(), ‘success’);。你需要提前在数据库中创建好test_summary表。设置工作流定时画布上的任务关系DAG已经定义好了。点击画布右上角的“保存”按钮给工作流起个名字比如“Daily_Data_Pipeline”。保存后你可以点击“上线”按钮使其处于可调度状态。然后点击“定时”按钮设置一个调度时间。例如设置为“每天凌晨1点执行”。这里你可以使用Cron表达式系统也提供了可视化生成器。4.3 手动运行与监控定时器设置好后工作流会在指定时间自动运行。但我们也可以手动触发一次立即验证流程是否正确。点击工作流定义列表操作栏的“运行”按钮。系统会弹出一个参数设置框本例中无参数直接点击“确认”即可。然后你需要切换到“工作流实例”页面。在这里你会看到刚刚生成的一条实例记录状态可能是“提交成功”、“运行中”。点击实例名称可以进入DAG视图这里会高亮显示当前正在运行的任务节点黄色已经成功的绿色失败的红色。你可以清晰地看到执行进度。点击某个任务节点比如那个Shell任务你可以查看它的“日志”。日志里会完整输出你脚本中的echo信息以及执行过程。这是排查任务失败原因最主要的手段。如果SQL任务失败了日志里会打印出具体的SQL错误信息。4.4 参数传递与上下文一个实用的工作流任务之间往往需要传递信息。DolphinScheduler提供了强大的参数系统。系统参数比如${system.biz.date}表示业务日期格式为yyyyMMdd。这在处理按天分区数据时非常有用。如果你的定时是每天跑那么这个参数会自动被替换为执行日期的前一天数据延迟一天处理是常态。自定义参数你可以在工作流或任务级别定义参数。在工作流定义页面点击“全局参数”可以添加一个参数比如input_path值为/data/input/${system.biz.date}。那么在Shell任务中你就可以用${input_path}来引用这个动态路径。上游传递Shell任务可以输出一些值比如echo “output100”。然后你需要在该Shell任务的“自定义参数”设置中定义一个“OUT”方向的参数比如叫record_count其值会从日志中通过正则表达式提取例如正则output(.*)。这样下游的SQL任务就可以用${record_count}来获取这个值并写入数据库。理解并熟练使用参数是构建灵活、可复用工作流的关键。它让你的工作流从静态的脚本集合变成了动态的、数据驱动的智能流程。5. 进阶配置与生产级考量当你成功运行了几个简单工作流后可能会遇到更实际的需求。下面这些进阶配置能帮助你将DolphinScheduler用于更严肃的场景。5.1 Worker分组与任务队列在Standalone模式下所有任务都在本地运行。但在生产集群中会有多个Worker服务器。你可以通过“Worker分组”来管理这些Worker。例如你可以创建“GPU_GROUP”和“CPU_GROUP”将不同类型的任务指派到不同的机器组上执行。在任务编辑界面高级设置里可以找到“Worker分组”选项。如果你创建了分组就可以在这里选择。同时每个任务都可以设置“优先级”当系统资源紧张时高优先级的任务会优先被派发执行。5.2 告警与失败重试没有人能保证任务永远成功。网络抖动、资源不足、数据异常都可能导致失败。因此配置告警和重试策略是必须的。失败重试在任务或工作流的“高级设置”中可以设置“失败重试次数”和“重试间隔”。例如设置重试3次间隔5分钟。这样任务失败后不会立即报警而是会自动重试几次很多临时性问题可以通过重试解决。告警策略在“监控中心”-“告警组管理”中可以创建告警组并添加需要接收告警的成员邮箱或钉钉、企业微信机器人Webhook。然后在“告警实例管理”中将告警组与你的工作流绑定。你可以设置“任务失败”、“任务超时”、“工作流失败”等多种告警条件。当条件触发时相关责任人会立即收到通知。5.3 补数与并发控制数据处理经常需要“补数”比如因为故障需要重新处理过去三天的数据。DolphinScheduler提供了强大的“补数”功能。在工作流实例页面你可以选择“补数”并指定一个日期范围如2024-05-01至2024-05-03。系统会自动为这三天各生成一个工作流实例并按照依赖关系依次或并行执行可配置。但补数或定时调度可能引发另一个问题并发。如果一个工作流执行时间过长超过了24小时那么第二天的定时实例就会启动导致同一个工作流有两个实例在同时运行可能会造成数据混乱。你可以在工作流定义的“高级设置”中开启“串行等待”开关。这样如果上一个实例还没结束新实例会进入“等待”状态直到上一个完成。5.4 关于“改造后构建打包”的思考社区热议的“dolphinscheduler改造后构建打包”通常涉及以下几个场景UI定制化企业可能需要修改前端界面替换Logo调整菜单或者增加一些特定的功能页面。这需要修改前端代码React然后重新打包构建前端资源。后端逻辑扩展比如增加一种新的任务类型集成公司内部的认证系统或者修改任务分发的逻辑。这需要修改后端Java代码。依赖升级为了解决安全漏洞或兼容性问题可能需要升级内部框架如Spring Boot的版本。改造后的构建流程通常是从官方GitHub仓库Fork代码在本地分支上进行修改。然后使用Maven进行后端编译打包mvn clean package -Prelease同时使用NPM构建前端npm run build。最后将构建出的dolphinscheduler-dist目录下的产物部署到生产环境。如果你所在团队有这类需求我的建议是先深入理解官方版本的部署和使用再考虑定制化。并且尽量将定制逻辑做成可插拔的插件而不是直接修改核心代码这样在未来版本升级时会轻松很多。6. 日常运维与避坑指南将DolphinScheduler用于生产环境后日常的运维和问题排查就成了必修课。分享几个我踩过的坑和总结的经验。6.1 日志查看与问题定位绝大多数问题都可以通过日志找到答案。日志分为几个层面服务日志在logs/目录下有dolphinscheduler-api-server.log,dolphinscheduler-master-server.log,dolphinscheduler-worker-server.log等。当工作流调度失败、任务无法下发时需要查看Master和Worker日志。当API调用出错时需要查看API日志。任务实例日志这是最常用的。在Web UI上进入工作流实例点击具体任务节点查看的日志实际上是Worker服务器执行该任务时产生的标准输出和标准错误。如果Shell脚本语法错误、SQL执行报错都会在这里显示。审计日志在Web UI的“安全中心”-“操作日志”中记录了所有用户的关键操作比如创建、删除、上线、下线工作流等用于安全审计。一个经典的排查流程是用户报告任务失败 - 去Web UI查看该任务实例日志 - 如果日志信息不明或任务处于“提交失败”状态 - 去对应Worker服务器的logs/目录下查看更详细的错误信息。6.2 资源管理别让“资源中心”成为摆设很多新手会忽略“资源中心”的功能习惯把脚本直接写在任务的输入框里。这对于简单的命令没问题但对于复杂的、需要复用的脚本这会导致维护困难。你应该将脚本文件.sh, .py, .sql上传到“资源中心”。在创建任务时选择“资源”而不是“直接输入”然后从资源中心选择你的脚本文件。这样做的好处是版本管理资源中心的文件可以更新、有历史记录。复用多个任务可以引用同一个脚本文件。权限控制可以对资源文件进行授权管理。确保你配置的resource.storage.type和resource.upload.path有足够的磁盘空间并定期清理旧的无用文件。6.3 数据库连接池与性能调优随着任务数量增多你可能会遇到数据库连接瓶颈。DolphinScheduler本身会频繁读写数据库来更新任务状态。如果发现Web界面操作变慢或者日志中出现获取数据库连接超时的错误可能需要调整数据库连接池配置。配置位于conf/spring-datasource.properties或相关配置文件中。你可以根据实际情况调整spring.datasource.hikari.maximum-pool-size最大连接数、connection-timeout连接超时等参数。不要盲目调大需要结合数据库服务器的性能和监控指标来设定。6.4 时间参数与时区陷阱这是一个高频踩坑点。我们之前提到过数据库连接串的时区。同样在任务中使用时间参数时也要格外小心。system.biz.date默认是调度时间的昨天格式yyyyMMdd。这是处理T1数据的标准用法。system.biz.curdate调度时间的当天格式yyyyMMdd。自定义日期格式你可以用${system.biz.date}进行运算比如在Shell中date -d “${system.biz.date} 1 days ago” %Y%m%d来获取前天的日期。关键点这些系统参数是基于DolphinScheduler服务器所在机器的系统时区计算的。务必保证服务器时区、数据库时区、以及你业务逻辑中预期的时区保持一致。最稳妥的做法是将服务器和数据库的时区都设置为统一的时区如Asia/Shanghai并在所有时间相关的操作中显式指定时区。从手动运维一堆零散的Crontab脚本到通过一个可视化平台统一管理成百上千个有复杂依赖的任务这个转变带来的效率和可靠性提升是巨大的。DolphinScheduler的学习曲线前期可能有些陡峭尤其是概念理解和环境配置阶段但一旦你画出了第一个能稳定运行的工作流后续的扩展就会顺畅很多。记住多利用它的可视化界面去观察任务依赖和运行状态遇到问题首先查看任务实例日志并善用参数化来构建灵活的工作流。