拓冰建站拓冰建站
首页 / 资讯中心 / 正文

ChunJun任务在DolphinScheduler中保存失败的六大根因与排查实战

做数据平台这几年我用DolphinScheduler编排过几百个工作流其中相当一部分节点是ChunJun的离线同步任务。最让我头疼的并不是ChunJun本身跑挂而是明明DAG画好了、参数填齐了点下保存却弹出一个保存失败整个工作流定义直接没法落库前面做的事全白费。ChunJun任务在DolphinScheduler工作流中保存失败这个问题我前前后后排查过不下二十次涉及JSON格式、插件依赖、元数据库锁、租户权限等各个层面今天就把这些坑一次性讲清楚。这篇内容适合正在维护DolphinScheduler集群的调度开发、数仓工程师也适合刚把FlinkX升级成ChunJun、正被保存问题折磨的团队参考。1. 先搞懂DolphinScheduler保存工作流时到底做了什么很多人一遇到保存失败就急着改ChunJun的JSON配置这方向其实不太对。要想快速定位问题你得先知道保存这个动作在系统内部走了一条什么样的链路。我建议每个做调度开发的人都把这条链路刻在脑子里后面排查问题会轻松很多。1.1 厘清DolphinScheduler与ChunJun在生态中的分工ChunJun的前身是FlinkX一个基于Apache Flink构建的分布式数据同步框架核心能力是把各类异构数据源之间的批量数据迁移做成统一配置、统一执行。它和DataX最大的区别有三个跑在Flink上所以天然支持分布式并行、支持断点续传、能复用Flink生态的上下游组件和监控体系。正因如此很多团队在离线数仓同步场景里会用ChunJun替代传统的单机同步工具。DolphinScheduler是分布式工作流调度平台提供可视化的拖拽式DAG编排。它本身不负责怎么同步数据只负责何时触发、在哪台Worker跑、用什么参数跑、跑完怎么通知下游。所以你会看到一种很常见的组合方式DolphinScheduler负责工作流编排和定时调度ChunJun负责真正的数据抽取和写入。在这个组合里ChunJun任务节点在DolphinScheduler中其实有两类形态。一类是官方内置的ChunJun任务插件节点类型直接选CHUNJUN页面里填JSON模板和参数另一类是把ChunJun包装成Shell脚本调用节点类型选SHELL脚本里写chunjun命令加上-job参数指定JSON文件。前者的保存链路更复杂出问题的概率也更大本文主要讨论前者但很多排查思路是通用的。1.2 保存工作流要经过“前端校验-后端API-元数据库”三层DolphinScheduler保存一个包含ChunJun节点的工作流并不是简单地把页面上的字段丢进数据库。它实际经历了三个阶段。第一阶段是前端校验。DolphinScheduler的UI在提交前会做一次拦截检查必填字段是否为空、任务类型是否存在、JSON字符串是否能被前端解析器读通。很多人在这一层就能看到明确提示比如任务名称不能为空ChunJun模板不能为空。如果你看到的是这类即时的红字提示说明问题出在表单层面。第二阶段是后端API处理。前端校验通过后UI会把整个工作流的DAG结构、每个节点的参数、任务之间的依赖关系封装成JSON对象通过HTTP接口提交到DolphinScheduler的api-server模块。api-server收到请求后会做几件事校验当前登录用户的权限、解析工作流定义JSON、把每个任务节点转换成任务定义对象、分配任务编码、处理租户和资源信息然后将数据处理结果交给DAO层。第三阶段是元数据库持久化。这是最终落库的环节涉及的主要表包括t_ds_process_definition工作流定义、t_ds_task_definition任务定义、t_ds_process_task_relation任务关系等。如果这一步因为数据库连接失败、唯一索引冲突、字段长度超限等原因失败前端往往只会收到一个笼统的错误码。理解这三层之后你会发现ChunJun任务保存失败的原因可能散落在任何一个环节并不一定是JSON写错了。所以我排查问题时第一件事永远是看报错来自哪个环节。1.3 把“保存失败”这个笼统问题拆成四类可操作的范围在动手之前我习惯先根据报错表现把问题分成四类这样能快速缩小排查范围。第一类是前端直接拦截的校验错误表现为某个字段旁边出现红字或者弹窗提示必填项缺失。这类问题最简单按提示补字段就行。第二类是后端返回的异常错误比如页面顶部弹出工作流定义保存失败或者一个红色的错误码但具体原因得看api-server日志。这类问题占大多数需要去日志里翻根因。第三类是请求超时类错误表现是点击保存后一直转圈最后提示超时或者网络异常。这类问题通常和数据库连接池、锁表、网络抖动有关而不是配置本身的问题。第四类是保存成功但数据不对比如工作流保存了但节点配置里的ChunJun参数被截断或者转义错误导致运行阶段才报错。这类问题最隐蔽因为保存这一关糊弄过去了。我后面讲的实战修复流程就是围绕这四类范围展开的。先把问题归到某一类效率能提升一倍。2. 深度拆解ChunJun任务保存失败的六大典型原因这一章节我总结了工作中反复踩过的六个根因按出现频率从高到低排列。你遇到保存失败时可以按这个顺序逐项排查。2.1 ChunJun任务JSON模板本身不合法最容易翻车先说实话ChunJun任务在DolphinScheduler中保存失败的头号原因就是节点上的JSON模板不是一个合法的JSON。很多人从网上或者同事那里复制一段ChunJun配置里面带着注释、尾逗号、单引号、甚至中文冒号自己肉眼看觉得没问题但后端解析器一解析就崩了。举个真实的例子。有一次同事在ChunJun模板里写了这样的配置片段{ reader: { name: mysqlreader, parameter: { connection: [{ jdbcUrl: [jdbc:mysql://10.0.0.10:3306/test], table: [user], querySql: [SELECT * FROM user WHERE status active AND name 张三] }] } } }从语法层面看这段JSON本身是合法的。但问题在于当这段内容作为ChunJun任务节点的自定义参数或模板内容存储时它会被整体放进一个更大的JSON字符串里内部所有的双引号、单引号都需要根据存储方式做转义。如果DolphinScheduler后端在序列化过程中遇到未转义的双引号或者前端在提交时没有正确编码就会出现JSON解析失败。还有一类更隐蔽的问题就是模板里出现了HTML转义字符。比如从网页上复制的配置双引号变成了中文引号或者减号变成了长短横线这类肉眼几乎看不出来的字符差异会让解析直接报错。我的建议是所有ChunJun模板在粘贴进DolphinScheduler之前先用本地工具做一次严格校验。最靠谱的命令是echo {job: {...}} | jq .如果能正常格式化输出说明JSON语法没问题。如果jq报错说明模板有语法问题先修好再贴进去。2.2 必填参数缺失与前后端校验规则不一致第二类高频原因是必填参数没填全但前端没有拦住。DolphinScheduler的Ul会对ChunJun任务节点做一层校验但UI版本的校验逻辑和后端api-server的校验逻辑不一定完全同步。常常有这种情况前端认为某个字段可以不填后端却把它当成必填项于是保存时后端直接抛异常。我遇到过的典型字段包括任务实例优先级比如HIGH/MEDIUM/LOW部分版本中后端API要求该字段不能为空。CPU配额和内存上限有些部署环境中Worker资源校验会介入字段格式不对保存失败。自定义参数里的JSON占位符工作流变量替换时如果找不到对应变量也可能在保存阶段被拦截。调度时间相关的配置如果工作流级别设置了定时调度但节点的超时告警或失败重试次数填成非法值保存也会报错。这类问题有一个共同特征报错信息往往比较含糊可能只提示保存失败或该字段值不合法不会明确指出是哪个字段。处理思路很简单逐个排查ChunJun任务节点的所有配置项确保每个字段都填写了规范值尤其是数字类型的字段不能写成空字符串。另外DolphinScheduler的工作流参数和节点参数是两个层面的概念。工作流级别可以定义全局参数节点级别可以定义局部参数。如果ChunJun模板里引用了类似${dt}这样的变量而这个变量只定义在工作流级别保存时节点本身的校验不会出问题但工作流级别的参数解析可能会失败导致整个保存请求被打回。2.3 元数据库连接池耗尽或表锁导致保存超时这类问题不太好一眼识别因为它跟你写的JSON一点关系都没有。DolphinScheduler会把工作流定义、任务定义都持久化到元数据库里如果数据库层面出了问题保存就会失败。我遇到过一种很典型的情况集群里有几个DolphinScheduler项目团队成员多大家一起高频保存工作流结果MySQL的连接数打满了。此时所有人点保存都会报错而且不光是ChunJun任务其他类型的任务节点也保存不了。表现是点击保存后页面卡住过几十秒弹出一个超时提示随后api-server日志里出现类似这样的记录CannotGetJdbcConnectionException: Failed to obtain JDBC Connection Caused by: java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after 30000ms另一种情况是元数据库表被锁住了。DolphinScheduler在保存大型工作流时会向t_ds_process_definition等表插入多条记录如果是MySQL的InnoDB引擎在高并发下可能出现行锁等待如果某个线程长时间持有事务未提交其他保存请求就会被阻塞最终超时。针对这类问题我的建议是先查数据库自身状态SHOW PROCESSLIST;重点看有没有大量Sleep状态的连接有没有长时间处于Waiting for table metadata lock的会话。如果有需要找到阻塞源头要么kill掉长时间空闲的连接要么优化应用的连接池配置。DolphinScheduler的api-server连接池参数可以通过环境变量或配置文件调整适当增大maximum-pool-size并设置合理的connection-timeout能缓解大部分连接不足的问题。2.4 租户、用户授权与资源中心权限引发保存失败DolphinScheduler的权限模型比很多开源调度系统都要细致它有用户、租户、项目、资源四级概念。表面上保存工作流是把DAG存下来实际上后端会校验当前用户对项目是否有写权限用户是否绑定了有效租户以及节点引用的资源文件是否在当前用户可访问的范围内。我踩过的一个坑是这样的某天数仓同学反馈ChunJun工作流保存失败报错信息是工作流定义保存失败租户信息不存在。排查后发现这个用户在用户管理列表里配置的租户被管理员删掉了导致后端在保存时组装不到租户ID直接中断。解决办法很简单重新给用户绑定一个有效租户问题就消除了。还有一类情况是ChunJun节点引用了资源中心的JAR包或者配置文件但当前用户对这个资源没有授权或者资源已经被移动到其他项目下后端在解析资源时找不到对应的文件记录同样会报保存失败。这里提醒一下资源中心的权限是独立的不是说你在这个项目里有权限就自动拥有所有资源的权限需要单独授权。要避免这类问题可以提前做一次自检用有管理员权限的账号打开用户管理确认每个需要保存工作流的用户都绑定了合法租户打开资源中心逐个检查ChunJun任务节点引用到的文件确认资源归属和授权关系都正常。2.5 插件JAR包缺失或版本不兼容导致保存阶段就报错很多团队在部署DolphinScheduler时为了让环境干净会把ChunJun任务插件单独放在一个目录然后通过配置指定加载路径。如果JAR包没有正确部署或者版本跟DolphinScheduler的api-server不兼容会出现一个很奇怪的现象前端能拉到ChunJun任务类型但保存时后端找不到任务类型的实现类直接抛出找不到类或者任务类型不支持的错误。之前有一次同事把ChunJun插件包从1.12升级到1.16版本结果api-server一直报错说某个类找不到。仔细看了堆栈发现新版插件框架的包名和类名发生了变化但DolphinScheduler的api-server加载器还在用旧类的反射方式创建任务实例最终导致保存ChunJun节点时失败。这个问题的本质是版本兼容性不是配置文件的问题。排查插件类问题时我一般做三步。第一步检查DolphinScheduler的lib目录和插件目录下是否存在chunjun相关的JAR包最好用命令确认find /opt/dolphinscheduler -name *chunjun* find /opt/dolphinscheduler -name *flinkx*第二步查看api-server启动时是否加载了这些JAR包有时候JAR包存在但权限不对导致进程读不到。第三步检查日志中的NoClassDefFoundError或ClassNotFoundException关键字定位具体的类名确认插件包是否完整。2.6 任务定义名称重复与历史版本冲突最后一种原因听着很小儿科但实际上很常见尤其是团队多人协作时。DolphinScheduler的任务定义表里任务名称和任务编码是有唯一性约束的。如果你在一个工作流里放两个ChunJun节点并且两个节点的任务名称设置成一样的或者两个不同工作流里的任务定义名称重复了保存时就可能触发唯一索引冲突报出类似Duplicate entry的错误。我记得有个项目组碰到过一个更隐蔽的场景他们在界面里删除了一个ChunJun任务但数据库里对应的记录没有清理干净或者只是把工作流下线了而任务定义还保留着。后来再创建一个同名任务时怎么保存都失败后端日志里能看到唯一索引冲突。这种问题光靠前端操作很难发现需要到元数据库里查一下SELECT id, code, name, task_type, version, project_code FROM t_ds_task_definition WHERE name 你起的任务名;如果有重复记录建议优先在页面上做下线或批量删除操作而不是直接改数据库。直接改库虽然能应急但会导致元数据和缓存不一致后面可能出现更诡异的问题。3. 实战修复从报错信息到问题定位的完整流程前面讲了原理层面的六大原因这一节给出一套可以直接照做的完整排查和修复流程。这套流程我总结成五个步骤从看到保存失败的报错开始到最终把任务跑通为止。3.1 第一板斧切到后端日志看真实报错信息点保存按钮之后很多人习惯盯着页面反复重试这种做法效率很低。正确操作是先把api-server的日志打开然后再去页面上复现一次保存动作用日志里的真实异常信息来判断问题方向。api-server日志一般在DolphinScheduler安装目录的logs下面文件名类似dolphinscheduler-api.log。可以用tail命令实时跟踪tail -f /opt/dolphinscheduler/logs/api-server/dolphinscheduler-api-*.log然后在页面上重新走一遍保存流程。日志出现后重点找Exception关键字。根据我的经验你会遇到的报错方向大约只有几类如果看到JsonParseException、JsonMappingException、Unexpected character基本就是ChunJun模板JSON格式问题。如果看到Duplicate entry、SQLIntegrityConstraintViolationException就是名称重复或主键冲突。如果看到CannotGetJdbcConnectionException、Connection is not available就是数据库连接池问题。如果看到ClassNotFoundException、NoClassDefFoundError就是插件依赖缺失或版本不兼容。如果看到Tenant not exists、User not found就是权限和租户问题。日志里的日志通常能定位到具体是哪个环节出的问题比前端那个干巴巴的保存失败有价值得多。3.2 第二板斧用最小化ChunJun任务做二分定位有时候日志信息不够直观或者报错确实模棱两可这时候我推荐一个非常高效的排查方法建一个最小的ChunJun任务只保留最基本的读写配置保存试试。所谓最小化任务就是去掉一切锦上添花的配置——不要增量同步、不要断点续传、不要限速、不要自定义变量、不要Kerberos认证。比如读一张MySQL小表往另一个MySQL库写只配置连接信息和表名。如果这个最小任务能保存成功说明ChunJun插件链路本身没问题问题出在你的复杂参数上比如某个变量没有被正确替换、某些参数格式不对等。接下来就可以从原任务里去掉一半参数再保存试试反复二分很快就能定位到是哪个参数在捣乱。如果最小化任务也保存失败那就基本可以确认问题不在JSON配置层面而在插件部署、元数据库、权限这些基础设施环节。这时候继续加配置只会把问题搞得更乱不如回到第一板斧认真看日志。3.3 第三板斧JSON格式规范与转义修复实操如果日志确认是JSON解析错误或者排查方向指向ChunJun模板格式问题那就需要把JSON模板单独拉出来处理。我个人的标准动作分三步。第一步把工作流里的ChunJun配置完整复制出来存成本地文件。第二步用jq做格式化校验jq . chunjun.json如果jq能正常输出整理后的JSON说明语法是通的。如果报错比如Unexpected token或Invalid string那就需要根据jq的报错行号去定位问题。第三步如果语法没有问题但保存仍然失败那就要考虑转义问题。DolphinScheduler里ChunJun任务节点在保存时会把chunjunJson字段作为一个大的JSON字符串存储在任务定义表里。也就是说你在前端模板框里写的内容最终会被嵌套进一个更大的JSON对象中。里面的双引号必须被正确转义单引号如果使用不当也可能破坏字符串边界。一个典型的修复案例是这样的。原配置里有一段SQLquerySql: SELECT * FROM user_table WHERE sign A如果直接把它嵌套到大的任务定义JSON里保存时后端可能把单引号当作字符串边界的一部分来处理导致解析出错。修复办法有两种。第一种是把SQL里的单引号统一改成双单引号或转移成Unicode表示第二种更稳妥——尽量别在ChunJun模板的SQL里写内联字符串常量而是通过参数方式传入。比如定义一个全局参数filter_condition在模板里写成querySql: SELECT * FROM user_table WHERE sign ${filter_condition}这样既方便后续维护又避免了转义带来的保存失败问题。3.4 第四板斧数据库层面确认约束和重复数据如果你已经确认JSON没有问题插件依赖也正常但是保存还是失败那就要回到数据库层面做检查。第一步确认元数据库能正常连接没有连接数打满和锁等待问题。建议在api-server所在机器上手动执行一条SQL验证数据库可用性SELECT 1;能返回1说明数据库本身是通的。然后再看连接池和锁问题参考本文第2.3小节的方法。第二步查询任务定义表确认是否有重复名称或孤立记录SELECT id, code, name, task_type, project_code, version FROM t_ds_task_definition WHERE name 你的任务名称;如果发现多条相同名称的记录多半是之前删除不彻底导致的。处理建议是先通过页面把相关任务下线如果页面已经看不到这些任务再在数据库中做一次清理。但注意清理数据库一定要先备份并且最好在维护窗口操作避免影响正在运行的任务。有些团队直接把t_ds_task_definition里的历史记录删掉结果第二天发现任务历史列表对不上号这种操作风险很高务必谨慎。第三步检查t_ds_process_definition表里是否有残留的相同工作流定义。工作流名称虽然允许重复但一些版本的DolphinScheduler在特定场景下会因工作流编码冲突导致保存失败这种情况可以把重建工作流定义作为预案。3.5 第五板斧保存之后立刻做一次空跑验证修复完成后我强烈建议不要只验证保存成功就收工而是紧接着做一次运行验证。因为ChunJun任务有一类经典问题就是保存时校验宽松、运行时校验严格。比如你在JSON里配置了一个Linkis或者Hive连接方式保存时后端不校验这个数据源的连通性但运行时ChunJun才会真的去连数据源如果连接信息不对任务会在运行阶段失败。还有一种情况是任务保存成功但ChunJun模板里的writer名称写错了比如写成mysqlwriter但实际期望的是mysqlwriter或postgresqlwriter保存时不报错运行起来却报任务类型找不到。所以正确的验收流程是保存成功之后在DolphinScheduler的工作流实例列表上选择手动执行然后观察一次完整的任务日志输出确认ChunJun被成功拉起来Flink作业进入RUNNING状态最后真正完成数据同步才算彻底解决。4. 常见问题速查表与独家经验分享最后这部分我把这些年遇到的高频问题整理成速查表再分享几个常规文档里不会写的经验。建议收藏起来下次再有人问ChunJun保存失败直接甩给他。4.1 ChunJun任务保存失败常见问题速查表现象日志或报错关键字根因修复方案点击保存立即报保存失败JSON parse error / Unexpected characterChunJun模板JSON不合法或转义错误jq校验模板处理单引号和双引号转义页面转圈后超时CannotGetJdbcConnectionException / request timed out元数据库连接池耗尽或网络超时查看数据库连接数调整api-server连接池配置只有ChunJun节点保存失败ClassNotFoundException / taskType not support插件JAR包缺失或版本不兼容检查插件目录确认插件包与DS版本匹配报错提示租户不存在Tenant not exists / user not found用户未绑定租户或租户被删除管理员重新绑定租户保存报Duplicate entrySQLIntegrityConstraintViolationException任务定义名称重复或残留旧数据页面清理重复任务必要时清理数据库冗余记录保存成功但运行失败运行日志里的ChunJun参数异常模板字段超过保存时校验范围手动执行任务根据运行日志调整模板参数这张表的核心思路是不要被保存失败四个字带着走先看日志关键字再判断根因最后对症下药。4.2 独家经验先把ChunJun任务在命令行跑通再进工作流这是我强烈建议每个团队都执行的操作规范。无论你用什么方式在DolphinScheduler里编排ChunJun都先单独把ChunJun的JSON配置放到一台能连接测试环境数据源的机器上用命令行执行一遍。ChunJun官方提供的启动方式是bin/chunjun -job /path/to/your/job.json如果这个命令能把数据同步跑通说明同步任务本身没问题接下来进DolphinScheduler时只需要关注调度层面的参数组装、变量替换和权限问题。反过来如果命令行压根跑不通那就算DolphinScheduler保存再成功也只是把一份有问题的配置存了下来运行一样会失败。这条经验帮我节省了大量联调时间。很多同事喜欢直接在DolphinScheduler页面上反复改参数、保存、运行、失败、再改整个过程非常低效。正确顺序一定是在本地把任务本身调通再放到调度平台上做集成验证。4.3 独家经验保存失败时先别动JSON看这4个字段在实际排查过程中我发现有四个字段特别容易引发保存失败但又最容易被忽视。它们分别是租户、资源权限、任务名称唯一性、自定义参数里的变量引用。这四个字段里租户和资源权限是DolphinScheduler权限模型里最容易出的问题任务名称唯一性是需要人工排查才能发现的元数据残留变量引用则是ChunJun模板和工作流参数之间的桥梁一旦变量名拼错保存阶段可能不报错但工作流整体解析时就会失败。所以我每次排查保存失败都会先问自己四个问题当前用户有没有绑定租户任务节点引用的资源有没有授权任务名称跟已有任务重不重模板里引用的变量是否在工作流参数或节点参数里有定义把这四个问题排查完90%的保存失败问题都能找到答案。4.4 版本升级之后的特殊注意点最后再提醒一个容易踩的场景从FlinkX迁移到ChunJun或者升级DolphinScheduler大版本后可能会出现旧任务能打开但不能重新保存的怪现象。这个现象多半是因为新旧版本的插件对任务定义的JSON结构要求发生了变化。比如FlinkX时代某些参数放在自定义参数区ChunJun版本后要求移到chunjunJson里或者DolphinScheduler 2.x的某个节点参数定义方式在3.x版本里不再被识别。此时即使你只是改了一个无关紧要的字段触发保存时后端也会用新规则去解析整份配置一旦发现旧字段不认识就会报保存失败。遇到这种情况我建议先看官方升级文档中关于ChunJun任务类型的变更说明然后创建一个新的ChunJun节点参考新节点的默认配置来调整旧节点的字段。千万不要硬怼也尽量别保留旧的模板结构不动否则后面每次保存都是一场斗争。说实话ChunJun任务在DolphinScheduler工作流中保存失败这个问题本身并不算多复杂但因为它跨越了前端表单校验、后端API逻辑、元数据库存储、插件加载机制好几个层面导致很多人排查起来没有头绪。我在实际运维中的体会是只要坚持先看日志、再定方向、后动手改三步走绝大多数问题都能在十分钟内定位出来。最后再说个小技巧每次修改ChunJun模板之前先把旧配置复制到本地留个备份一旦新配置还是不行可以用二分法快速回退到上一个可用的版本这个操作在多人协作的项目里尤其重要。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门