第 8 篇|Apache DolphinScheduler 与 Flink Spark 数据引擎的边界、协同与最佳实践

团队会不自觉地让调度系统承担越来越多“本不属于它”的职责,比如在调度层写复杂业务逻辑、控制计算参数,甚至试图统一管理不同计算引擎的执行细节。


点亮⭐️  

https://github.com/apache/DolphinScheduler

在数据平台不断演进的过程中,一个非常常见但又隐蔽的误区是:团队会不自觉地让调度系统承担越来越多“本不属于它”的职责,比如在调度层写复杂业务逻辑、控制计算参数,甚至试图统一管理不同计算引擎的执行细节。短期来看似乎提升了效率,但从长期来看,这种设计往往会让系统变得高度耦合、难以维护,甚至在规模上来之后失去稳定性。

因此,在讨论具体实践之前,我们必须先把一件事情讲清楚:调度系统与数据引擎之间的边界。

调度系统与数据引擎的职责边界


要理解整个体系的运行方式,可以先记住一个非常核心的原则:调度系统只负责“什么时候运行”和“依赖关系”,而具体“如何计算”,必须交给 Spark、Flink 或 SeaTunnel 这样的执行引擎。换句话说,DolphinScheduler 是流程的编排者,而不是计算的执行者。

从工程视角来看,这种分工可以用一张表清晰表达:

组件
核心职责
DolphinScheduler
DAG 编排、任务调度、依赖管理、失败重试
Spark
离线批处理计算
Flink
实时流处理
SeaTunnel
数据集成(批处理 / 流处理 / CDC)

在实际开发中,这条边界最容易被打破的地方,往往是 Shell 任务。很多人习惯在一个节点里写复杂的分支逻辑,例如根据日期决定执行不同的 Spark 作业:

if [ "$day" == "2026-04-01" ]; then  spark-submit job_a.pyelse  spark-submit job_b.pyfi

这种写法虽然“能跑”,但会带来三个问题:首先,逻辑被隐藏在脚本中,DAG 无法感知;其次,依赖关系不再清晰,影响调度系统的可视化能力;最后,后期运维和排障成本会显著增加。

而更合理的方式,是将分支逻辑显式建模在工作流中,通过条件节点来控制执行路径,让整个流程在界面上是可见、可控的。

批处理、流处理与CDC的调度差异


当职责边界清晰之后,再来看不同类型任务的调度方式,就会发现它们在本质上是三种完全不同的模式,而不是同一种调度逻辑的简单变体。

首先是批处理任务,这是最符合传统调度模型的一类场景,例如数仓中的 T+1 任务或按小时运行的聚合计算。这类任务有明确的时间窗口,并且上下游依赖关系清晰,非常适合通过 DAG 来表达。

在实践中,通常会按照 ODS、DWD、DWS 进行分层拆分,每一层对应一个或多个独立任务,并通过参数(如 ${biz_date})进行驱动。例如一个典型的 Spark 提交方式如下:

spark-submit \  --class com.example.ETLJob \  --master yarn \  --deploy-mode cluster \  etl-job.jar \  --date ${biz_date}

在这个过程中,调度系统的职责是串联任务关系、控制执行顺序以及处理失败重试,而不应该深入到具体的计算逻辑中。

与批处理形成鲜明对比的是流处理任务。流处理的本质是“持续运行”,而不是“被周期性触发”。如果用调度系统每隔几分钟去启动一次 Flink 作业,本质上是在用错误的方式解决问题。

一个设计合理的流任务,应该依赖 Flink 自身的状态管理和 checkpoint 机制长期运行,而 DolphinScheduler 在这里扮演的角色,更像是一个“守护者”,负责初次启动、状态检测以及异常恢复,而不是频繁干预。

进一步来看 CDC 场景,它本质上也是流处理的一种,但更偏向于数据集成,这正是 SeaTunnel 的典型应用场景。通过 SeaTunnel,可以非常方便地实现数据库到消息队列的实时同步,例如从 MySQL 到 Kafka:

env {  execution.parallelism = 2}source {  MySQL-CDC {    hostname = "localhost"    port = 3306    username = "root"    password = "123456"    database-names = ["test_db"]    table-names = ["test_db.user"]  }}sink {  Kafka {    topic = "user_cdc"    bootstrap.servers = "localhost:9092"  }}

对应的启动命令如下:

./bin/seatunnel.sh \  --config config/mysql_cdc.conf \  -e local

调度层面,CDC 与流处理的原则是一致的:只启动一次,长期运行,并通过状态检测机制保证稳定性,而不是通过周期调度反复触发。从这个角度来看,批处理、流处理和 CDC 的核心区别,其实在于“是否需要被重复调度”。

为什么调度系统不应该侵入计算引擎


当系统规模逐渐扩大之后,一个更深层的问题就会浮现出来:为什么我们反复强调调度系统要保持“克制”? 原因在于,一旦调度系统开始侵入计算引擎的职责范围,整个架构的可控性就会迅速下降。

例如,在调度脚本中直接写入 Spark 的资源参数:

spark-submit \  --executor-memory 8\  --conf spark.sql.shuffle.partitions=500 \  job.sql

这种做法的问题在于,它把执行层的配置硬编码进了调度层,使得参数管理分散且难以统一。一旦需要调整资源配置,就必须修改调度任务,甚至重新发布工作流。而更合理的方式,是将这些参数放在 Spark 配置中心或作业内部管理,让 DolphinScheduler 只负责触发执行:

spark-submit job.sql

这种解耦方式可以显著提升系统的可维护性,使每一层都专注于自己的职责。

从整体架构来看,一个成熟的数据平台通常可以抽象为三层结构:最上层是以 DolphinScheduler 为代表的调度层,负责流程编排;中间是以 Spark、Flink、SeaTunnel 为核心的执行层,负责具体计算与数据处理;最底层是 YARN 或 Kubernetes 这样的资源层,负责资源分配与隔离。只有当这三层边界清晰时,系统才能在复杂度提升的同时保持稳定性。

SeaTunnel实战架构示例


在真实生产环境中,这种分层思想通常会体现在完整的数据链路中。例如,可以通过 SeaTunnel 实现 MySQL 到 Kafka 的 CDC,同步实时数据;随后由 Flink 进行实时计算,产出在线指标;同时将数据落地到存储系统,再由 Spark 完成离线数仓加工。在这个过程中,DolphinScheduler 负责统一编排这些任务,包括启动 CDC、监控流任务以及调度离线计算。

从流程上看,可以抽象为一条清晰的数据链路:数据从源端进入,通过 SeaTunnel 进入实时通道,由 Flink 处理后服务在线系统,同时落地到存储,再由 Spark 完成分层加工,而 DolphinScheduler 始终作为“中枢”,协调各个环节的执行顺序与依赖关系。

总结:让系统回归“各司其职”


当我们回到最初的问题,其实可以用一句话总结整个体系的设计原则:DolphinScheduler 是“大脑”,而 Spark、Flink、SeaTunnel 是“肌肉”。调度系统负责决策与编排,而执行引擎负责具体计算与处理。

在实际落地中,可以进一步归纳为三条简单但非常关键的原则:第一,所有流程逻辑必须体现在 DAG 中,而不是隐藏在脚本里;第二,所有计算逻辑必须下沉到执行引擎内部,避免调度层膨胀;第三,流处理和 CDC 任务必须以“常驻运行”为前提设计,而不是按批处理思路调度。

当这三点被严格执行之后,数据平台就能够从“能跑”逐步演进到“稳定、可扩展、可治理”,这也是从工程化走向体系化的关键一步。




END






用户案例


Cisco Webex天翼云Zoom网易邮箱 每日互动 惠生工程作业帮 博世智驾蔚来汽车 长城汽车集度长安汽车思科网讯食行生鲜联通医疗联想新网银行兴业证券唯品富邦消费金融 自如有赞伊利当贝大数据珍岛集团传智教育BigoYY直播  拈花云科太美医疗深圳某智能制造企业



迁移实战


Azkaban   Ooize(当贝迁移案例)airflow (有赞迁移案例)Air2phin(迁移工具)Airflow



最新发版消息



Apache DolphinScheduler 3.4.1 发布,新增任务分发超时检测



加入社区


关注社区的方式有很多:

  • GitHub: https://github.com/apache/dolphinscheduler
  • 官网:https://dolphinscheduler.apache.org/en-us
  • 订阅开发者邮件:dev@dolphinscheduler@apache.org(向邮箱发送任意内容,收到邮件后回复同意订阅即可)
  • X.com:@DolphinSchedule
  • YouTube:https://www.youtube.com/@apachedolphinscheduler
  • Slack:https://join.slack.com/t/asf-dolphinscheduler/shared_invite/zt-1cmrxsio1-nJHxRJa44jfkrNL_Nsy9Qg

同样地,参与Apache DolphinScheduler 有非常多的参与贡献的方式,主要分为代码方式和非代码方式两种。

非代码方式包括:

完善文档、翻译文档;翻译技术性、实践性文章;投稿实践性、原理性文章;成为布道师;社区管理、答疑;会议分享;测试反馈;用户反馈等。

‍代码方式包括:

查找Bug;编写修复代码;开发新功能;提交代码贡献;参与代码审查等。

贡献第一个PR(文档、代码) 我们也希望是简单的,第一个PR用于熟悉提交的流程和社区协作以及感受社区的友好度。

社区汇总了以下适合新手的问题列表https://github.com/apache/dolphinscheduler/pulls?q=is%3Apr+is%3Aopen+label%3A%22first+time+contributor%22

优先级问题列表https://github.com/apache/dolphinscheduler/pulls?q=is%3Apr+is%3Aopen+label%3Apriority%3Ahigh

如何参与贡献链接https://dolphinscheduler.apache.org/zh-cn/docs/3.2.2/%E8%B4%A1%E7%8C%AE%E6%8C%87%E5%8D%97_menu/%E5%A6%82%E4%BD%95%E5%8F%82%E4%B8%8E_menu

如果你❤️小海豚,就来为我点亮Star吧!

https://github.com/apache/dolphinscheduler



你的好友秀秀子拍了拍你

并请你帮她点一下“分享”