DolphinScheduler 3.2.2 集成 SeaTunnel 任务启动失败问题排查与解决方案

5小时前学习8

9129263df661e42ce1a673a55d1c1148.png

一、问题背景

在使用 Apache DolphinScheduler 3.2.2 调度 SeaTunnel 数据同步任务时,发现任务在 DolphinScheduler 中执行失败。

SeaTunnel 本身安装正常,手动在服务器上执行 SeaTunnel 命令也能够正常运行,但是通过 DolphinScheduler 的:

bash ./bin/start-all.sh

启动集群后,再执行 SeaTunnel 任务会出现以下错误:

18_132.sh: 行 4: /bin/seatunnel.sh: 没有那个文件或目录

经过排查发现:

  • 手动启动 Worker 时,SeaTunnel 任务可以正常执行;
  • 使用 start-all.sh 启动 DolphinScheduler 后,SeaTunnel 任务执行失败;
  • SeaTunnel 安装目录实际存在;
  • DolphinScheduler Worker 的 SEATUNNEL_HOME 环境变量在不同启动方式下存在差异。

最终定位到问题根因:

DolphinScheduler 的 dolphinscheduler-daemon.sh 在启动 Worker 时,会使用 bin/env/dolphinscheduler_env.sh 覆盖 Worker 自己的 conf/dolphinscheduler_env.sh。

因此,仅修改:

worker-server/conf/dolphinscheduler_env.sh

并不能保证通过 start-all.sh 启动后仍然生效。


二、环境信息

本次环境主要信息如下:

项目 配置
DolphinScheduler 3.2.2
SeaTunnel 本地部署
操作系统 Linux / Ubuntu
Java OpenJDK 17
DolphinScheduler目录 /usr/local/server/dolphinscheduler
SeaTunnel目录 /usr/local/server/seatunnel
Worker目录 /usr/local/server/dolphinscheduler/worker-server
Worker端口 1234

SeaTunnel 实际安装位置:

/usr/local/server/seatunnel

正常情况下需要:

SEATUNNEL_HOME=/usr/local/server/seatunnel

这样 DolphinScheduler 执行 SeaTunnel 时:

${SEATUNNEL_HOME}/bin/seatunnel.sh

才能正确解析为:

/usr/local/server/seatunnel/bin/seatunnel.sh


三、故障现象

DolphinScheduler 执行 SeaTunnel 任务时,日志出现:

18_132.sh: 行 4: /bin/seatunnel.sh: 没有那个文件或目录

从任务执行命令来看:

${SEATUNNEL_HOME}/bin/seatunnel.sh \
    --config /tmp/dolphinscheduler/exec/process/default/185039101090048/185039137408256_2/18/132/seatunnel_18_132.conf \
    --deploy-mode cluster

正常情况下:

${SEATUNNEL_HOME}
        ↓
/usr/local/server/seatunnel
        ↓
/usr/local/server/seatunnel/bin/seatunnel.sh

但是实际错误变成:

${SEATUNNEL_HOME}
        ↓
空
        ↓
/bin/seatunnel.sh

因此可以初步判断:

问题不是 SeaTunnel 的 seatunnel.sh 不存在,而是 DolphinScheduler Worker 执行任务时没有获得 SEATUNNEL_HOME。


四、首先确认 SeaTunnel 本身是否正常

先检查 SeaTunnel:

ls -l /usr/local/server/seatunnel/bin/seatunnel.sh

如果能够看到:

/usr/local/server/seatunnel/bin/seatunnel.sh

说明 SeaTunnel 文件本身存在。

然后测试:

/usr/local/server/seatunnel/bin/seatunnel.sh --help

如果能够正常输出 SeaTunnel 帮助信息,则说明:

  • SeaTunnel 安装正常;
  • Java 基础环境基本正常;
  • seatunnel.sh 本身可以执行。

进一步测试环境变量:

export SEATUNNEL_HOME=/usr/local/server/seatunnel

$SEATUNNEL_HOME/bin/seatunnel.sh --help

如果正常,则进一步证明问题集中在:

DolphinScheduler Worker → 环境变量

而不是 SeaTunnel 本身。


五、第一次排查:修改 Worker 环境文件

DolphinScheduler Worker 使用:

/usr/local/server/dolphinscheduler/worker-server/conf/dolphinscheduler_env.sh

因此最初的解决方法是在该文件中增加:

export SEATUNNEL_HOME=/usr/local/server/seatunnel

检查:

grep -n "SEATUNNEL_HOME" \
/usr/local/server/dolphinscheduler/worker-server/conf/dolphinscheduler_env.sh

如果存在:

export SEATUNNEL_HOME=/usr/local/server/seatunnel

再手动执行 Worker:

/usr/local/server/dolphinscheduler/worker-server/bin/start.sh

此时 SeaTunnel 任务可以正常运行。

这说明:

worker-server/conf/dolphinscheduler_env.sh 中增加 SEATUNNEL_HOME 是有效的。

但是问题并没有彻底解决。


六、为什么手动启动可以,start-all.sh 却不行?

这是本次问题最关键的地方。

手动启动:

/usr/local/server/dolphinscheduler/worker-server/bin/start.sh

与:

bash ./bin/start-all.sh

实际上不是完全相同的启动路径。

6.1 手动启动路径

手动启动大致为:

worker-server/bin/start.sh
        ↓
读取
worker-server/conf/dolphinscheduler_env.sh
        ↓
读取 SEATUNNEL_HOME
        ↓
启动 Worker

因此手动启动时:

export SEATUNNEL_HOME=/usr/local/server/seatunnel

能够正常生效。


七、start-all.sh 的实际启动流程

检查:

/usr/local/server/dolphinscheduler/bin/start-all.sh

可以发现 Worker 并不是直接调用:

worker-server/bin/start.sh

而是:

bash bin/dolphinscheduler-daemon.sh start worker-server

也就是说:

start-all.sh
    ↓
dolphinscheduler-daemon.sh
    ↓
worker-server/bin/start.sh

真正关键的是中间这一层:

dolphinscheduler-daemon.sh


八、发现真正的根因:环境文件会被覆盖

查看:

cat /usr/local/server/dolphinscheduler/bin/dolphinscheduler-daemon.sh

其中存在:

function overwrite_server_env() {
  local server=$1
  local server_env_file="${DOLPHINSCHEDULER_HOME}/${server}/conf/dolphinscheduler_env.sh"

  if [ -f "${BIN_ENV_FILE}" ]; then
    echo "Overwrite ${server}/conf/dolphinscheduler_env.sh using bin/env/dolphinscheduler_env.sh."
    cp "${BIN_ENV_FILE}" "${server_env_file}"
  else
    echo "Start server ${server} using env config path ${server_env_file}, because file ${BIN_ENV_FILE} not exists."
  fi
}

其中:

BIN_ENV_FILE="${DOLPHINSCHEDULER_HOME}/bin/env/dolphinscheduler_env.sh"

而 Worker 启动时执行:

overwrite_server_env "${command}"

因此实际发生的是:

/usr/local/server/dolphinscheduler/bin/env/dolphinscheduler_env.sh
                ↓
                ↓ cp
                ↓
/usr/local/server/dolphinscheduler/worker-server/conf/dolphinscheduler_env.sh

也就是说:

worker-server/conf/dolphinscheduler_env.sh 并不是最终的配置源。

它会在 DolphinScheduler 使用 dolphinscheduler-daemon.sh 启动 Worker 时被覆盖。


九、完整问题链路

整个问题可以表示为:

                    DolphinScheduler
                           │
                           ▼
                    start-all.sh
                           │
                           ▼
              dolphinscheduler-daemon.sh
                           │
                           ▼
                 overwrite_server_env()
                           │
                           │
              ┌────────────┴────────────┐
              │                         │
              ▼                         ▼
bin/env/dolphinscheduler_env.sh    worker-server/conf/
                                  dolphinscheduler_env.sh
              │                         ▲
              │                         │
              └────────── cp ──────────┘
                                        │
                                        ▼
                              worker-server/bin/start.sh
                                        │
                                        ▼
                              读取 dolphinscheduler_env.sh
                                        │
                                        ▼
                              SEATUNNEL_HOME 是否存在?
                                        │
                         ┌──────────────┴──────────────┐
                         │                             │
                        是                             否
                         │                             │
                         ▼                             ▼
              /usr/local/server/             ${SEATUNNEL_HOME}
                  seatunnel                  为空
                         │                             │
                         ▼                             ▼
           /usr/local/server/seatunnel/       /bin/seatunnel.sh
               bin/seatunnel.sh                     │
                                                     ▼
                                                  ❌ 失败


十、正确解决方案

10.1 不应该只修改 Worker 配置文件

之前修改:

/usr/local/server/dolphinscheduler/worker-server/conf/dolphinscheduler_env.sh

虽然可以让手动启动生效,但是:

start-all.sh

启动时会重新覆盖该文件。

因此不推荐只修改这里。


10.2 修改统一环境配置

正确配置文件应该是:

/usr/local/server/dolphinscheduler/bin/env/dolphinscheduler_env.sh

首先检查:

grep -n "SEATUNNEL_HOME" \
/usr/local/server/dolphinscheduler/bin/env/dolphinscheduler_env.sh

如果没有结果,则增加:

echo 'export SEATUNNEL_HOME=/usr/local/server/seatunnel' >> \
/usr/local/server/dolphinscheduler/bin/env/dolphinscheduler_env.sh

然后确认:

tail -n 10 \
/usr/local/server/dolphinscheduler/bin/env/dolphinscheduler_env.sh

应该能够看到:

export SEATUNNEL_HOME=/usr/local/server/seatunnel


十一、重新启动 DolphinScheduler

修改统一配置之后,需要重新启动服务。

进入:

cd /usr/local/server/dolphinscheduler

停止:

bash ./bin/stop-all.sh

检查 Worker:

ps -ef | grep WorkerServer | grep -v grep

确认旧 Worker 已经停止后,再执行:

bash ./bin/start-all.sh


十二、验证配置是否被正确复制

启动完成以后,首先检查:

grep -n "SEATUNNEL_HOME" \
/usr/local/server/dolphinscheduler/worker-server/conf/dolphinscheduler_env.sh

应该看到:

export SEATUNNEL_HOME=/usr/local/server/seatunnel

这是因为:

bin/env/dolphinscheduler_env.sh
        ↓
dolphinscheduler-daemon.sh
        ↓
overwrite_server_env()
        ↓
worker-server/conf/dolphinscheduler_env.sh

已经完成了正确的配置复制。


十三、进一步检查 Worker 进程环境

仅检查配置文件还不够,最好检查实际运行中的 Worker JVM 环境。

先找到 Worker PID:

ps -ef | grep WorkerServer | grep -v grep

例如得到:

dolphin+ 153245 ... org.apache.dolphinscheduler.server.worker.WorkerServer

然后:

PID=153245

cat /proc/$PID/environ | tr '\0' '\n' | \
grep -E 'SEATUNNEL_HOME|DOLPHINSCHEDULER_HOME|JAVA_HOME'

正常应该至少包含:

SEATUNNEL_HOME=/usr/local/server/seatunnel

这样才能证明:

SEATUNNEL_HOME 不仅写入了配置文件,而且真正进入了 Worker 进程环境。


十四、最终验证 SeaTunnel 任务

重新执行 DolphinScheduler 中的 SeaTunnel 任务。

任务命令:

${SEATUNNEL_HOME}/bin/seatunnel.sh \
--config /tmp/dolphinscheduler/exec/process/default/.../seatunnel_18_132.conf \
--deploy-mode cluster

此时应该被正确解析为:

/usr/local/server/seatunnel/bin/seatunnel.sh \
--config /tmp/dolphinscheduler/exec/process/default/.../seatunnel_18_132.conf \
--deploy-mode cluster

不再出现:

/bin/seatunnel.sh: 没有那个文件或目录


十五、建议增加一项启动检查

为了以后避免类似问题,可以在部署完成后执行:

echo "===== DolphinScheduler Environment ====="

echo "DOLPHINSCHEDULER_HOME=$DOLPHINSCHEDULER_HOME"
echo "SEATUNNEL_HOME=$SEATUNNEL_HOME"
echo "JAVA_HOME=$JAVA_HOME"

echo "===== SeaTunnel ====="

ls -l "$SEATUNNEL_HOME/bin/seatunnel.sh"

如果:

SEATUNNEL_HOME=

或者:

ls: cannot access .../seatunnel.sh

就不要继续执行任务,应先修复环境变量。


十六、另一个独立问题:Java 17 的 InaccessibleObjectException

在排查过程中还发现了另外一个异常:

java.lang.reflect.InaccessibleObjectException:
Unable to make field private final int java.lang.ProcessImpl.pid accessible:
module java.base does not "opens java.lang" to unnamed module

这个问题与:

/bin/seatunnel.sh: 没有那个文件或目录

不是同一个问题。

前者属于:

DolphinScheduler
        ↓
Java 17
        ↓
反射访问 JDK 内部字段
        ↓
Java Module System
        ↓
InaccessibleObjectException

后者属于:

DolphinScheduler Worker
        ↓
SEATUNNEL_HOME
        ↓
环境变量没有传递
        ↓
/bin/seatunnel.sh

因此排查时应该分开处理。


十七、Java 17 问题的处理方向

当前 Worker 使用:

Java 17

而 DolphinScheduler 相关代码中存在:

java.lang.ProcessImpl.pid

等反射访问。

后续可以检查 Worker 的:

/usr/local/server/dolphinscheduler/worker-server/bin/jvm_args_env.sh

以及实际启动参数:

ps -ef | grep WorkerServer | grep -v grep

重点确认是否需要增加类似:

--add-opens=java.base/java.lang=ALL-UNNAMED

对于另外出现的:

java.lang.invoke.SerializedLambda.capturingClass

则可能涉及:

--add-opens=java.base/java.lang.invoke=ALL-UNNAMED

不过这属于第二阶段问题。

建议先确认 SeaTunnel 调度链路恢复正常,再单独处理 Java 17 反射兼容问题。


十八、排查过程中最容易犯的错误

错误一:只修改 worker-server 配置

例如:

vim /usr/local/server/dolphinscheduler/worker-server/conf/dolphinscheduler_env.sh

增加:

export SEATUNNEL_HOME=/usr/local/server/seatunnel

然后认为问题已经解决。

实际上:

start-all.sh
    ↓
dolphinscheduler-daemon.sh
    ↓
overwrite_server_env()

会覆盖这个文件。


错误二:只测试手动启动

worker-server/bin/start.sh

正常并不代表:

start-all.sh

正常。

因为两种启动路径不同。

因此排查 DolphinScheduler 服务环境问题时,应优先验证实际生产启动方式。


错误三:看到 /bin/seatunnel.sh 就认为 SeaTunnel 没安装

实际上:

/bin/seatunnel.sh

这个路径本身就暴露了问题。

如果正确配置:

SEATUNNEL_HOME=/usr/local/server/seatunnel

最终路径应该是:

/usr/local/server/seatunnel/bin/seatunnel.sh

因此:

/bin/seatunnel.sh

实际上说明:

${SEATUNNEL_HOME} 没有展开出有效值。


十九、推荐的最终配置结构

建议把 DolphinScheduler 与 SeaTunnel 的环境配置统一管理:

/usr/local/server/dolphinscheduler/
│
├── bin/
│   ├── start-all.sh
│   ├── stop-all.sh
│   ├── dolphinscheduler-daemon.sh
│   │
│   └── env/
│       └── dolphinscheduler_env.sh    ← ★统一配置源
│
├── worker-server/
│   ├── bin/
│   │   └── start.sh
│   │
│   └── conf/
│       └── dolphinscheduler_env.sh    ← daemon启动时覆盖
│
└── ...

统一配置:

# SeaTunnel
export SEATUNNEL_HOME=/usr/local/server/seatunnel

这样:

start-all.sh
       ↓
dolphinscheduler-daemon.sh
       ↓
bin/env/dolphinscheduler_env.sh
       ↓
worker-server/conf/dolphinscheduler_env.sh
       ↓
worker-server/bin/start.sh
       ↓
Worker JVM
       ↓
SeaTunnel Task

整个链路的环境变量才能保持一致。


二十、总结

本次问题最终可以归纳为:

表面错误

/bin/seatunnel.sh: 没有那个文件或目录

直接原因

SEATUNNEL_HOME 为空

深层原因

通过:

start-all.sh

启动 DolphinScheduler 时:

dolphinscheduler-daemon.sh

会执行:

overwrite_server_env "${command}"

将:

bin/env/dolphinscheduler_env.sh

复制覆盖:

worker-server/conf/dolphinscheduler_env.sh

而 SEATUNNEL_HOME 之前只配置在 Worker 自己的配置文件中,所以被覆盖后丢失。

正确解决方案

将:

export SEATUNNEL_HOME=/usr/local/server/seatunnel

配置到:

/usr/local/server/dolphinscheduler/bin/env/dolphinscheduler_env.sh

然后重新执行:

cd /usr/local/server/dolphinscheduler

bash ./bin/stop-all.sh

bash ./bin/start-all.sh

最后验证:

grep -n "SEATUNNEL_HOME" \
/usr/local/server/dolphinscheduler/worker-server/conf/dolphinscheduler_env.sh

以及:

PID=$(pgrep -f 'org.apache.dolphinscheduler.server.worker.WorkerServer' | head -1)

cat /proc/$PID/environ | tr '\0' '\n' | \
grep SEATUNNEL_HOME

预期:

SEATUNNEL_HOME=/usr/local/server/seatunnel

核心经验:在 DolphinScheduler 中,通过 start-all.sh 启动服务时,应优先修改 bin/env/ 下的统一环境配置,而不是只修改各 Server 自己的 conf/ 环境文件。

扫描二维码推送至手机访问。

版权声明:本文由星光下的赶路人发布,如需转载请注明出处。

本文链接:https://forstyle.cc/zblog/post/130.html

分享给朋友: