
简介这是Kettle 9.4版本的完整资源包即Pentaho Data Integration 9.4PDI 9.4面向需要安装、配置与维护ETL数据集成工具的开发、运维及数据工程师。Kettle是业界常用的开源ETL工具9.4版在转换、作业调度、大数据集成等方面支持较为成熟。压缩包共1082个文件大小约358MB以630个jar依赖库、196个ktr转换文件、80个xml配置文件和19个kjb作业文件为主体另含Spoon、Kitchen、Pan等启动脚本及示例流程能帮助使用者快速搭建PDI环境并理解核心组件与目录结构。已有7617人学习下载。通过这批文件可掌握Kettle更名后的常见文件组织方式、转换与作业的保存格式以及命令行调用方法对后续开发数据同步流程、维护调度任务和排查配置问题具有直接参考价值。1. Kettle 9.4 先搞清三件事它是什么、能干什么、适合谁Kettle官方叫 Pentaho Data Integration简称 PDI9.4 是社区版里稳定性很好的一套开源 ETL 工具。Kettle 9.4 解决的问题很直接数据从 Excel、CSV、业务库到目标库之间的抽取、清洗、转换和加载不用为每个迁移场景反复写 Java 或 Python 脚本可视化拖拽就能完成大部分工作。适合数据工程师、实施交付人员以及要接手一堆 SQL 脚本但不想被绑定在某一套代码里的人。这篇笔记按我实际拆过的环境来写从下载安装、图形界面到 Linux 无界面部署把会遇到的坑按顺序排一遍。2. 安装部署 PDI 9.4JDK 版本、下载与启动参数2.1 下载与版本核对从压缩包到目录结构搜Kettle下载时容易被最新版本吸引但 9.4 不是最新就是最好。9.4 经过社区长期修补稳定性比 9.3 明显好又不像 10.x 那样对 JDK 版本、插件新语法要求苛刻。很多公司内部存量作业还是基于 9.x 开发的接手时版本对不上重新迁移转换文件成本不低。如果你还在用 JDK 8先别急着解压9.4 的启动脚本默认要求 JDK 11这一点后面单独说。下载回来的压缩包一般是 zip 格式命名类似 pdi-ce-9.4.x-stable.zip解压后核心目录叫># 解压 Kettle 9.4 压缩包到 /opt 目录 unzip pdi-ce-9.4.x-stable.zip -d /opt # 进入核心目录 cd /opt/data-integration # 查看关键可执行文件和目录是否完整 ls -l spoon.sh kitchen.sh pan.sh carte.sh ls -ld lib plugins ui解压目标路径不要带中文、不要带空格否则后续连接资源库、加载驱动时容易出现路径解析问题。目录结构里lib 放核心 jar 和第三方数据库驱动plugins 是插件扩展目录ui 是界面资源。真正在命令行调度用到的是四个脚本spoon.sh 是图形客户端kitchen.sh 跑作业pan.sh 跑转换carte.sh 启动远程执行服务。怎么确认下载的版本没搞错解压完后看 lib 目录下 pentaho 相关 jar 的文件名或者直接调用 kitchen 脚本并带版本参数# 打印 Kettle 版本号正常能看到 9.4.x 和构建时间 ./kitchen.sh -version如果这里就报错说明 JDK 还没配对直接进下一节。我一般会在这一步顺便确认脚本有执行权限没有就 chmod x 补上。2.2 JDK 与环境变量版本选型最忌凭感觉PDI 9.4 官方要求 JDK 11这一点值得反复强调。用 JDK 8 启动 spoon.sh大概率只闪一个启动画面就退出日志里报 Unable to determine java version 或 UnsupportedClassVersionError用 JDK 17 某些发行版会遇到模块化访问限制。所以最稳妥的做法是单独装一个 JDK 11不要动系统全局 Java。注意PDI 9.4 启动脚本查询 Java 的顺序是先看环境变量 PENTAHO_JAVA_HOME再看 JAVA_HOME最后才找 PATH 里的 java。很多人以为设置了 JAVA_HOME 就完事却忽略了 PENTAHO_JAVA_HOME 这个优先级最高的变量。特别是当服务器上同时存在多个 JDK 时登录 shell 里生效的 JAVA_HOME 和 Kettle 启动时实际使用的 Java 经常不是同一个。我一般的做法是单独建一个 JDK 目录然后按下面这样配置环境变量# 编辑 /etc/profile 或 ~/.bashrc追加以下内容 export JAVA_HOME/opt/jdk-11.0.21 export PENTAHO_JAVA_HOME$JAVA_HOME export PATH$JAVA_HOME/bin:$PATH # 使配置生效并验证版本 source ~/.bashrc java -version注意输出里必须明确看到 Java 11.x 或 openjdk 11而不要看到 1.8。如果服务器上有多个 JDK 且不方便改全局配置就把 PENTAHO_JAVA_HOME 写死在启动 wrapper 脚本里而不是依赖用户登录时加载的 profile。原因很直接crontab 定时任务和 ssh 非交互登录时不会加载 .bashrc这个问题在第 4 章会专门讲。2.3 启动 Spoon 与内存参数默认值未必适合本地电脑图形界面版的 Spoon 是大多数人第一次认识 Kettle 的入口。解压后执行 spoon.bat 或 ./spoon.sh新手经常遇到两个现象窗口还没出来就闪退或者拖几个大数据量步骤就内存溢出。闪退的原因不一定是电脑配置差而是脚本里默认启动参数不合适。打开 spoon.sh在文件头部能找到一段参数配置改起来很简单# 修改 spoon.sh / spoon.bat 中的 JVM 启动参数 export PENTAHO_DI_JAVA_OPTIONS-Xms1024m -Xmx2048m -Dfile.encodingUTF-8 # -Xms 是 JVM 初始堆大小-Xmx 是最大堆大小 # -Dfile.encodingUTF-8 强制 JVM 使用 UTF-8避免中文乱码把 -Xmx2048m 改成 -Xmx4096m 是常规操作但前提是机器物理内存够大。另一个细节是别只调大 -Xmx 却不调 -Xms两者差距过大时 JVM 会频繁扩容GC 压力反而升高。Kettle 图形界面本身比较吃内存加上数据库驱动和插件堆内存 2G 是起步4G 不算浪费。改完参数再启动能看到 Spoon 窗口和左下角插件加载日志就算成功。第一次启动建议直接新建一个空转换打开左侧主对象树确认步骤节点能正常拖拽。如果这里就开始转圈卡死多半是 plugins 目录里残留了不兼容的第三方插件把 plugins 目录整体备份后删掉重来比逐个排查快得多。3. 转换与作业拖拽之外参数、日志与调度3.1 转换 vs 作业什么时候用哪个Kettle 里最容易混淆的是 .ktr转换和 .kjb作业。很多初学者把多步骤数据流全部画在转换里然后在里面加如果否则的逻辑最后数据流和控制流搅在一起运行结果完全不可控。转换的本质是一条数据流管道表输入到字段选择再到表输出数据像水一样流过每个步骤步骤之间可以并行执行。作业的本质是控制流编排一个步骤执行完再决定下一步做什么可以判断、循环、发邮件也可以嵌套另一个作业。两者最常见的配合方式是单次抽取清洗用转换定时调度和分支流程用作业作业里挂转换。维度转换.ktr作业.kjb执行模型步骤间并行流水线步骤间串行控制流适用场景单条数据链路抽取清洗多作业编排、分支、循环、调度失败处理任一步骤失败则整体失败可配置成功或失败跳转文件后缀.ktr.kjb记忆方法很简单数据在转换里流动逻辑在作业里编排。像先删表再重建再去抽取这种多阶段方案放在作业里而不是在转换里连箭头。判断标准是如果两个步骤之间有明确的先后依赖且需要失败分支就必须拆到作业层。3.2 第一个转换从 CSV 到目标表的完整节点配置把一个最常见的例子拆开讲把一张 CSV 文件导入 MySQL字段做完类型转换后落地。Spoon 的拖拽操作不细说重点是几个容易设错的地方。CSV 输入步骤需要配三样东西文件路径、文件编码、分隔符和表头。常见翻车点是文件编码Windows 下 Excel 导出的 CSV 经常是 GBK而 Kettle 默认按 UTF-8 读取中文会变成乱码或问号。判断文件实际编码可以用 file -i 命令输出结果里有 charset 字段按它来设置 CSV 输入的编码属性。表输出步骤的提交大小Commit size是第二个坑点。默认值可能是 1000目标库是 PostgreSQL 时配合大批量写入建议调成 5000MySQL 在事务里大批量插入时中途遇到脏数据回滚成本也不低。我的习惯是先用几百行的小数据集试跑确认字段类型映射没问题再切到线上量级。命令行运行转换的常见做法是直接用 pan.sh# 用 pan.sh 执行转换-file 指定 .ktr 文件路径 # -level:Basic 输出每步读写行数最容易定位瓶颈 ./pan.sh -file:/opt/etl/import_user.ktr -level:Basic参数说明-file 后面跟绝对路径路径别带空格-level 有 Error、Minimal、Basic、Detailed、Debug、Rowlevel 几档Basic 是生产环境最常用的级别。需要给转换传参数时追加 -param:fileName/data/user.csv 这种写法多个参数就写多个 -param。跑完看日志末尾的 Finished processing 和行数统计。日志里只看到开始和结束数据量是正常的因为大批量数据被分批处理了如果中途报错优先看日志里的步骤名称而不是整个堆栈。这一步能跑通说明你的转换基本可用。3.3 作业里加循环与变量让 ETL 跑得可复用单次转换能跑通下一步就是重复执行。很多人直接把命令挂到 crontab然后发现每个月都要改文件路径这就是作业参数化没做好的结果。Kettle 作业里可以设置命名参数和变量。命名参数作用域是当前作业变量可以跨转换传递引用方式统一是 ${参数名}。比如文件路径写成 ${inputFile}日期写成 ${opDate}。参数名尽量用英文驼峰避免中文变量在某些插件里解析异常。定义命名参数的操作是打开作业属性切到参数页签写参数名和默认值。然后在命令行执行时用 -param 覆盖默认值# kitchen.sh 执行作业并传参 ./kitchen.sh -file:/opt/etl/monthly_report.kjb \ -param:inputFile/data/monthly/users_2025.csv \ -param:opDate2025-01-01 \ -level:Basic这种设计的好处是作业本身不写死环境相关信息。开发环境传测试路径生产环境传生产路径同一个 .kjb 文件两边都能跑。变量引用优先级要记住命令行 -param 设置的最高其次是作业自身变量最后是 kettle.properties 里的全局变量。同名变量产生困惑时按这个顺序排查覆盖关系。作业里做循环也依赖变量。常见做法是用作业执行器配合条件判断步骤判断当前批次号是否达到上限每次循环加一中间结果写到变量里。这个方案比直接用 JavaScript 步骤更稳定因为 Kettle 内置的脚本引擎在不同发行版里版本不完全一致写出跨版本可用的 JS 并不省心。4. Linux 部署 PDI 9.4 踩坑记录无界面运行要绕开的五个坎如果只是本机拖一拖界面这一章的坑大概率遇不到。但实际交付时ETL 基本都部署在 Linux 服务器上用 kitchen.sh 和 pan.sh 跑批。这一章算是我在 linux 环境部署 kettle 过程中用血泪经验换来的五个坎每条都按现象、原因、解决记录按部署顺序排列。4.1 环境变量失效与 JDK 检测失败现象ssh 登录后在终端手动执行 /opt/data-integration/kitchen.sh 正常但用 crontab 定时执行时反复报 PENTAHO_JAVA_HOME is not set 或 Java not found。原因crontab 的默认 shell 环境不是交互式登录环境它不加载 /etc/profile 和用户 .bashrc。而 Kettle 的启动脚本依赖 JAVA_HOME 或 PENTAHO_JAVA_HOME 决定用哪个 Java 启动 JVM变量一丢脚本直接退出。解决不要依赖登录环境变量把 JDK 声明写成启动 wrapper 脚本。这是我现成在用的模板#!/bin/bash # ETL 任务启动 wrapper固定 JDK 路径避免环境变量缺失 export JAVA_HOME/opt/jdk-11.0.21 export PENTAHO_JAVA_HOME${JAVA_HOME} export KETTLE_HOME/opt/data-integration export PATH${JAVA_HOME}/bin:${PATH} # 日志目录先创建再执行作业标准输出和错误全部落盘 mkdir -p /var/log/etl cd ${KETTLE_HOME} || exit 1 ./kitchen.sh -file:/opt/etl/jobs/nightly.kjb -level:Basic /var/log/etl/nightly.log 21注意最后一行把标准输出和错误输出一起重定向到日志否则 crontab 会把输出发到系统邮箱真正要看日志时反而找不到。从那以后我所有 Linux 部署脚本都强制走这个 wrapper 模式。4.2 X11 报错与无界面启动方式选型现象在无桌面的 Linux 服务器上执行 ./spoon.sh报错 Failed to connect to the X server 或 Cannot open display。原因spoon 是纯 GUI 程序必须依赖 X Window 环境。服务器没装图形界面或者 ssh 连接没做 X11 转发自然起不来。解决换用 pan.sh 跑转换、kitchen.sh 跑作业这才是无界面服务器上的正确用法。如果真的需要图形化调试本地开发机用 Spoon 把转换编辑好传到服务器后执行即可没有必要在服务器上硬跑 GUI# 验证无界面模式能正常运行 /opt/data-integration/kitchen.sh -file:/opt/etl/test.kjb -level:Basic # 再验证 pan.sh 执行转换 /opt/data-integration/pan.sh -file:/opt/etl/test.ktr -level:Basic如果坚持给服务器装 xvfb 做虚拟显示生产环境真的不值得多一个虚拟显示进程就多一个不稳定因素。服务器上的日志文件和数据行数统计才是监控依据把 Spoon 当监控台用是架构上的误区。4.3 Carte 端口占用与跨机调度现象启动 ./carte.sh 0.0.0.0 8081 后浏览器访问 http://服务器IP:8081/kettle/ 一直转圈或提示连接被拒绝。原因Carte 是 PDI 的远程执行服务默认监听 8081 端口。连接被拒绝通常是端口被占用、防火墙未放行、或者 Java 进程根本没起来。解决先指定地址和端口启动再用 curl 探活# 指定监听地址和端口启动 Carte后台运行 ./carte.sh 0.0.0.0 8082 sleep 5 # 探活接口HTTP 200 说明服务正常 curl -I http://127.0.0.1:8082/kettle/status跨机调度时最容易踩的坑是进程起来了但监听的不是 0.0.0.0 而是 127.0.0.1本机 curl 正常、远端访问失败。遇到这种情况先检查 ss -lntp | grep 8082看到 127.0.0.1 就把启动参数里的地址改成 0.0.0.0。Carte 端口只建议在内网开放完全没必要暴露到公网。4.4 中文乱码与编码不统一现象CSV 在 Windows 上打开正常导入 MySQL 后中文全部变成问号或者日志里中文变成一串转义符。原因三个环节编码不一致。CSV 文件本身是 GBKJVM 默认字符集是 UTF-8数据库连接字符串里没指定字符集参数三层不一致就会乱码。解决统一三层编码。第一层CSV 输入步骤的编码属性显式指定 GBK 或 UTF-8第二层启动脚本加 -Dfile.encodingUTF-8第三层JDBC URL 后面加 characterEncodingutf8。以 MySQL 为例URL 写成 jdbc:mysql://127.0.0.1:3306/dbname?useSSLfalsecharacterEncodingutf8。# 在 wrapper 里补充 JVM 编码参数 export PENTAHO_DI_JAVA_OPTIONS-Xmx4096m -Dfile.encodingUTF-8判断文件实际编码优先用 file -i /data/file.csv 命令输出里的 charset 字段是设置依据比靠经验猜可靠。另外要注意Kettle 9.4 本身在 Linux 下的默认编码是 UTF-8和 Windows 下的 GBK 习惯不同跨平台迁移作业时编码属性必须逐个检查。4.5 定时任务调度权限与日志落盘现象crontab 里配了每天凌晨执行 kitchen.sh第二天发现任务没执行或者执行了但没有任何日志翻 /var/spool/mail/root 才发现里面一堆报错。原因crontab 里的相对路径找不到文件、执行用户没有目标目录权限、日志目录不存在导致重定向失败三个因素叠加起来任务就静默失败了。解决定时任务用绝对路径命令外层包 bash日志先落盘再吞掉 crontab 的标准输出# crontab -e 示例每天 01:30 执行 30 1 * * * /opt/etl/bin/run_nightly.sh /dev/null 21配套的 run_nightly.sh 里第一件事就是检测日志目录是否存在不存在就用 mkdir -p 创建再用 date 命令生成带日期的日志文件名避免日志文件被无限撑大。第二天早上只需要检查一个日志目录不需要去翻系统邮件。一个细节是 crontab 脚本内部不要再使用相对路径 cd依赖当前目录的写法在定时任务里是最脆弱的。5. 数据库连接与资源库驱动、连接池与常见报错5.1 资源库配置文件资源库 vs 数据库资源库Kettle 本身不强制使用资源库可以把 .ktr / .kjb 文件直接保存到磁盘。但多人协作时文件互相覆盖、版本混乱几乎是必然的这时候资源库就派上用场了。9.4 支持两种文件资源库和数据库资源库。文件资源库是一个 .kdb 文件适合单人本地开发拷贝方便缺点是缺少并发锁和权限控制。数据库资源库会在目标库里建一组以 R_ 开头的表多人共享同一套作业避免互相覆盖。选择建议很明确个人练习用文件资源库交付团队用数据库资源库。对比项文件资源库.kdb数据库资源库存储位置本地磁盘文件目标数据库 R_ 系列表适合场景单人开发、便携团队共享、版本管理并发支持弱多编辑容易冲突强有锁机制配置复杂度低需要指定库并初始化表数据库资源库的初始化不是手动的在 Spoon 连接配置里指定已有库后R_ 系列表会由 Kettle 首次连接时自动创建。如果连不上或看不到对象树第一件事检查该库账号有没有建表权限而不是反复测试连接。资源库连接测试通过和资源库表可用是两回事。5.2 驱动加载与类冲突连接失败的前三原因连不上数据库是最高频的翻车点。最常见现象是连接时提示 ClassNotFoundException 或 No suitable driver found再或者报 Error occurred while trying to connect。原因排名前三驱动 jar 没放到 lib 目录、驱动版本和数据库版本不匹配、多个驱动 jar 同时存在于 classpath 导致类冲突。解决顺序也按这个来先确认驱动文件存在# 检查 MySQL 8.x 驱动是否已放到 lib 目录 ls -l /opt/data-integration/lib/mysql-connector-java-8*.jar # 如果不存在把下载好的 jar 拷贝进去然后重启 Spoon 或重新执行 cp /opt/drivers/mysql-connector-java-8.0.33.jar /opt/data-integration/lib/驱动类名不要写错。老版本的 com.mysql.jdbc.Driver 在 MySQL 8 里已废弃要换成 com.mysql.cj.jdbc.Driver。Oracle、PostgreSQL、SQL Server 的常用配置我整理成了表格数据库JDBC URL 示例驱动类建议驱动版本MySQL 8jdbc:mysql://127.0.0.1:3306/dbname?useSSLfalsecharacterEncodingutf8com.mysql.cj.jdbc.Driver8.0.33PostgreSQLjdbc:postgresql://127.0.0.1:5432/dbnameorg.postgresql.Driver42.xOraclejdbc:oracle:thin:127.0.0.1:1521/orcloracle.jdbc.OracleDriver对应数据库版本的驱动SQL Serverjdbc:sqlserver://127.0.0.1:1433;databaseNamedbnamecom.microsoft.sqlserver.jdbc.SQLServerDriver12.x提示MySQL 8 请使用 com.mysql.cj.jdbc.Driver老驱动类名在新版本驱动里已经移除了。驱动放进去后如果依然报错把 lib 和 ext_libs 里重复的 jar 清理一遍只保留一个版本。不同版本驱动类冲突的排查方式是看堆栈里 classloader 信息但更快的解决方式是直接删掉低版本驱动。5.3 连接参数与事务边界不要忽略 autoCommit表输出步骤的连接设置里隐藏着一个容易被忽略的属性使用事务和自动提交。默认行为是每个批次提交一次但如果目标表有外键或触发器大批量写入时会出现部分成功、部分失败日志里报错却看不到失败行因为事务已经回滚了。我的一般做法是小批量测试时用自动提交方便定位脏数据大批量跑批时关闭自动提交把提交大小设成 1000 到 2000。这样内存占用不会飙太高单条脏数据只回滚当前批次后续批次继续执行。另一个边界问题是连接被占满。一个转换里同时挂多个表输出步骤时Kettle 会为每个步骤创建独立连接连接数可能超过数据库连接池上限报 Too many connections。解决思路有两个减少并行步骤数量或者共享同一个数据库连接并在表输出步骤中开启连接池最小连接数 2、最大连接数 5 足够多数场景别贪多。6. 进阶技巧作业参数化、增量同步与验证手段部署稳定之后我才真正体会到参数化和增量同步的价值。第一次做月度批处理时我手动改日期参数某个月忘了改跑了整整一周错误数据才发现。从那以后我强制所有作业都走一遍参数化改造日期、文件路径、目标表名全部用 ${} 占位命令行只传当天执行参数。增量抽取的核心是记录上一次同步水位。常见做法是把 max(update_time) 写入一张控制表下一次执行时先读出水位再跑。这一步的坑在于格式统一日期字段别混用 12 小时制和 24 小时制否则 lag 判断会差一天。-- 表输入步骤中的增量 SQL 写法 -- ${beginDate} 和 ${endDate} 由命令行传入 SELECT * FROM orders WHERE create_time ${beginDate} AND create_time ${endDate}验证手段我习惯三步走。第一步用 -level:Debug 跑一次小数据量看每个步骤的读写行数行数对不上就是字段映射或过滤条件有问题第二步用 count 语句核对目标表行数与源表差异超预期就要查类型转换丢行第三步在作业末尾加一个行数校验步骤把源和目标行数差写出来非零就触发告警。# 生产执行时固定使用 Basic 日志级别 ./kitchen.sh -file:/opt/etl/incremental.kjb \ -param:beginDate2025-01-01 \ -param:endDate2025-02-01 \ -level:Basic日志级别是个细节Debug 和 Rowlevel 输出量巨大上亿行的表能把磁盘打满生产环境只保留 Basic 和 Error真正排错时再临时切 Detailed。Kettle 9.4 日志按时间滚动保留周期按磁盘配额定我一般保留 14 天足够回溯问题。最后被很多人忽略的一点所有作业脚本结束前打印一行退出码到日志crontab 根据退出码判断是否告警非 0 就触发通知这样批处理万一翻车不用等第二天手动翻日志。希望帮到你。本文还有配套的精品资源点击获取