
简介Kettle 6.0 是面向数据仓库与数据集成场景的开源 ETL 工具适合数据工程师、数仓开发者在异构数据源之间完成抽取、清洗、转换与加载适用于数据仓库构建、报表数据预处理、日常数据同步等任务。压缩包共含 2000 个文件以 1353 个 jar 依赖包为主同时包含 ktr/kjb 作业与转换、xml 配置文件、bat/sh 启动脚本等整体约 849.79 MB解压后可直接部署使用。已有 607 人学习下载。包内提供 Spoon、Kitchen、Carte 等核心启动器以及 carte-config、jdbc.properties 等配置示例覆盖 Windows 与 Linux 环境随包附带的转换与作业样例能直观展示工作流调度、MySQL/Oracle/CSV/Excel 等多数据源接入、字段映射、去重、空值处理等常见预处理操作适合初学者作为入门模板也便于老手快速定位所需工具。借助这些内容读者可以快速搭建 Kettle 6.0 环境理解 ETL 流程设计思路并以此为基线扩展自己的数据集成项目整体目录结构清晰、分类明确。 很多朋友看到我还在维护 Kettle 6.0 时都会问这都什么年代了怎么还在用这么老的 ETL 工具说实话我也想过切到新版但手里几十个跑了好几年的数据迁移作业全是用 Kettle 6.0 搭的。KettlePentaho Data Integration这个开源 ETL 工具核心价值就是让你用图形化拖拽的方式完成数据的抽取、转换和加载对中小团队的离线数仓、库表迁移、接口数据采集来说它足够直观也足够稳。这篇文章不是 Kettle 6.0 的完整手册而是我从下载安装开始到实际处理数据库迁移、API 分页采集、国产数据库适配时踩过的一堆坑和总结出来的门道。如果你正在用 Kettle 6.0或者准备接手一套老环境可以直接参考。1. 老ETL工具Kettle 6.0凭什么还在项目里坚挺1.1 图形化ETL解决的是数据搬运的最后一公里先聊点基础的。ETL 是 Extract-Transform-Load 的缩写说白了就是三件事从源系统把数据抽出来按业务规则做清洗和转换最后加载到目标库。Kettle 这类工具的价值在于你不需要写一堆 Python 脚本去处理每种数据源而是用 Spoon 图形界面把“表输入”“字段选择”“表输出”这些步骤像搭积木一样串成一条转换跑起来就行了。Kettle 6.0 虽然界面老但这个核心设计放到今天依然高效我接触过的很多团队甚至把复杂的报表取数逻辑也放在 Kettle 里做。对于没有专职大数据平台、又要做跨系统数据同步的团队来说Kettle 6.0 几乎是零门槛。它不需要写 MapReduce不需要搭集群一台普通服务器装个 JDK 就能跑。而且它的日志和错误处理很直观哪一行数据出了问题、哪个字段转换失败一眼就能看到比黑盒脚本好排查得多。1.2 6.0版本的适用边界离线批量是它的舒适区很多人问为什么不升级到 8.0 或 9.x我的答案很简单升级成本大于收益。Kettle 8.0 后Pentaho 把不少组件往大数据生态靠界面也重做了一版但很多老转换在新版本里需要重新调试驱动、调整组件参数换一次版本等于把线上作业全部回归一遍。而 6.0 这个版本在离线批量、数据库到数据库的迁移场景里稳定性极其出色社区里能搜到的问题几乎都有答案。当然6.0 也有明显的边界。它不适合做实时流处理对超大表千万级以上的抽取性能一般也没法直接对接太多现代 SaaS 接口。你如果是要做实时数仓或数据湖那别犹豫直接上 Flink、Spark 那套但如果你是做每日定时同步、把 A 库的数据洗到 B 库Kettle 6.0 仍然是一个性价比很高的选择。我在项目里甚至跑过两年多没重启过的定时作业稳得让人想不起来它的存在。2. 装好Kettle 6.0第一步就卡住的环境细节2.1 JDK版本、内存参数和驱动放置位置Kettle 6.0 对 JDK 版本非常挑装太高版本会直接打不开或者运行时报 NoClassDefFoundError。我自己长期用的是JDK 1.8准确说最好是 8u202 之前的版本因为 8u202 之后 Oracle 调整了授权策略某些环境下 Kettle 会报奇怪的 JCE 问题。如果你只有 JDK 11 以上那大概率会在启动 Spoon 时挂在 AWT 或 SWT 库上别恋战直接装个 1.8。内存参数是另一个容易被忽略的点。Spoon 默认启动内存偏小处理大转换时经常卡死。我习惯在>PENTAHO_DI_JAVA_OPTIONS-Xmx2048m -Xms512m -XX:MaxPermSize256m注意 6.0 还需要设置 MaxPermSize不然用久了 PermGen 会溢。数据库驱动 jar 不要乱放统一扔到libext/JDBC目录下。比如连接 MySQL 要用mysql-connector-java-5.1.49.jar千万别直接用 8.x因为 8.x 驱动的类名变成了com.mysql.cj.jdbc.DriverKettle 6.0 注册驱动时经常识别不到。2.2 Spoon闪退与资源库选择Spoon 闪退多数是 SWT 图形库和系统不兼容导致的。在 Linux 服务器上跑经常缺libwebkitgtk之类的库建议先执行yum install -y webkitgtk如果是 CentOS 7 以下还要确保libXext、libXrender、libXtst这些基础图形库装全。Windows 底下闪退则多半是 JDK 版本不对或者杀毒软件把 jar 锁了换个目录、关掉实时防护再试。还有一个很多人第一次用就卡住的选择题资源库用哪种Kettle 6.0 默认会引导你建 Pentaho RepositoryJackrabbit这个模式在服务端部署时容易锁库多人同时改作业会冲突。我的建议是本地开发直接用文件资源库把.ktr和.kjb存在 Git 里管理配合版本回溯比用内置资源库舒服太多。如果团队非要统一管理再去配数据库资源库但要保证数据库驱动已经放进libext/JDBC否则资源库连接界面根本加载不出驱动列表。3. 数据库迁移全流程表输入、动态SQL与字段校验的实战组合3.1 表输入到表输出先别急着拖动组件很多新手一上来就拖一个“表输入”和一个“表输出”然后直接填SELECT * FROM table结果跑出来一堆乱码和类型报错。这里有几个我踩过无数次坑后的固定套路首先表输入的 SQL 里永远不要写SELECT *。就算源表和目标表字段完全一致也建议显式列出字段名。为什么因为在 Kettle 中字段的元数据是提前从 SQL 里解析出来的你写*它也能解析但碰到某些 JDBC 驱动的返回结果不规范时字段类型会全部变成 String后面做类型转换就麻烦了。其次表输出组件里的“批量插入”大小要设置合理。默认可能是 100我一般调到 1000 到 5000配合“提交大小”一起用。但注意如果目标表有大量索引批量太大反而会拖慢速度这个时候我会先删索引、导完数据再重建整体时间能缩短一半以上。3.2 动态SQL变量一条作业跑多个表Kettle 6.0 里写的 SQL 不是死的它支持变量替换。例如你定时同步多个业务分表可以建一个“表输入”SQL 写成SELECT * FROM ${source_table} WHERE update_time ${last_time}然后在作业中通过“Set Variables”步骤把source_table和last_time这两个变量传进去。这个方法非常实用我常用来做增量同步作业先执行 SQL 查出上次同步的时间赋值给变量再执行转换转换里的表输入读取变量拼 SQL跑完后再用“SQL 脚本”步骤更新同步时间。有一个细节必须注意表输入组件里有个“替换 SQL 中的变量”选项默认是勾选的。如果你在 SQL 里写了一个类似${xxx}的字符串而它恰好不是你要替换的变量记得在组件属性里把变量设置成默认值或者关掉全局替换否则会直接把$开头的字符串当成变量解析报错。我在对接接口时经常遇到 JSON 字段里带$的情况第一次没注意排查了大半天。3.3 字段校验让脏数据在门口就被拦住热搜词里提到“kettle检验字段的值组件怎么使用”确实这个组件名字很绕。在 Kettle 6.0 的转换分类里它叫Validator中文界面显示为“校验字段的值”。它的作用是对输入流的字段做规则校验符合条件的行进入下一个步骤不符合的行则走到“错误处理”分支。我举个例子。从 Excel 导入一批客户数据时需要校验手机号是否为 11 位数字、金额字段是否大于 0、必填字段是否为空。Validator 支持非常灵活的多规则配置选择字段然后添加规则规则类型包括“必填”“数据类型”“数值范围”“允许值列表”“正则表达式匹配”等。把校验通过的输出接到“表输出”把不通过的接到“写日志”或“插入错误表”就能做到脏数据不落地还能看到每一条被拦下的原因。实际使用中我建议把校验规则尽量做在转换的源头而不是目标表前。因为目标表前校验时数据已经经过了很多计算定位问题时很难分清是原始数据的问题还是转换脚本的问题。在源表输入后立刻校验一遍后面所有步骤都基于干净数据排查效率会高很多。4. API分页、循环读取与达梦/TDengine适配的硬仗4.1 REST Client加作业循环API分页数据的标准打法Kettle 6.0 的“REST Client”组件在“查询”分类下可以发送 GET、POST 等请求。但很多人第一次用它的时候会困惑它只能发一次请求怎么处理分页答案是不能光靠一个转换要配合作业的循环能力。我的标准做法是写一个转换专门负责执行单页请求。转换里用“REST Client”组件URL 中动态拼接当前页数比如https://api.example.com/list?page${page}size100然后请求结果直接进“JSON Input”组件提取data数组里的字段最后落到目标表。这个转换每次只处理一页。再写一个作业先用“Set Variables”把page设为 1然后执行这个转换执行完后用“Simple Evaluation”步骤判断当前页返回的条数是否等于每页大小如果等于说明可能还有下一页就把page加 1再循环回去如果小于每页大小说明已经到最后一页直接结束循环。4.2 循环读取API的作业设计经验循环读取 API最怕出现死循环和重复拉取。我的经验是在作业的“Simple Evaluation”里除了判断页数据量还要加一个最大页数限制比如设定page 200才继续。这个保护非常重要有些接口在数据量刚好是每页大小的整数倍时最后一页会再返回一页空数据不加限制就可能一直拉下去。另外接口限流也是绕不开的问题。Kettle 6.0 的 REST Client 本身没有并发控制如果你在转换里开了多线程很容易把对方接口打挂。我的做法是在每页请求的转换开头加一个“阻塞”步骤Blocking Step或者在作业里用“延迟”步骤强制等 200 毫秒。很多外部 API 没有兜底限流被拉挂了对方第一个找的就是你。还有一点API 返回的 JSON 结构变化很频繁。Kettle 6.0 里“JSON Input”的字段映射是配置在组件里的如果接口字段名变了转换不会自动适配所以做离线采集时最好在作业里加一步“检查返回码”用“过滤记录”或“校验字段的值”判断code 200不是 200 就发告警或停下来别让脏数据进去。4.3 达梦、TDengine迁移到MySQL的兼容处理现在国产数据库用得越来越多热搜词里提到的“kettle支持taos数据库迁移到mysql”就是典型场景。Kettle 6.0 对达梦、TDengine 这类数据库没有原生向导但通过 JDBC 驱动器可以连只是要处理不少坑。达梦DM驱动 jar 一般是DmJdbcDriver18.jar放到libext/JDBC后在“表输入”里选 Generic Database连接 URL 写成jdbc:dm://192.168.1.10:5236/DMSERVER驱动类填dm.jdbc.driver.DmDriver。达梦的 SQL 方言和 Oracle 比较像表名和字段名默认是大写如果你在 MySQL 里建了反引号包裹的小写字段迁移时全要处理掉。最好在源表 SQL 里显式给字段起别名例如SELECT ID AS id, NAME AS name FROM TAB1这样 Kettle 的输出字段名就和 MySQL 对齐了。TDenginetaosJDBC 驱动在 2.x 时代比较老Kettle 6.0 加载没问题但是 TDengine 的 SQL 有自己的一套比如时间序列数据库的timestamp字段类型Kettle 的元数据解析不一定认。我实际操作时会在表输入 SQL 里把复杂类型先转换掉SELECT _c0, _c1, cast(ts as varchar(50)) AS ts_str FROM my_table用cast把timestamp转成字符串Kettle 的 JDBC 驱动就能稳定读取。落库到 MySQL 时再把ts_str映射到datetime字段。这种方式虽然绕了一层但好在稳定不用担心驱动类型映射异常。5. Kettle 6.0的稳定性调优与Elasticsearch插件边界5.1 内存溢出、增量同步与批量提交Kettle 6.0 跑大任务时最常见的问题就是内存溢出尤其是在使用“排序记录”“去重记录”这类需要把数据放进内存的步骤时。要减少内存压力我一般会先看数据量级如果单表超过几百万行排序和去重就不要放在转换里做而是把数据先落到目标库再用 SQL 去重或者分片抽取。增量同步是另一个性能关键。全量同步最容易内存溢出优化思路很简单只抽取增量数据。可以在源表上加update_time条件也可以用“表输入”里的“自动建议”做增量。我自己常用时间戳增量每次更新作业里的last_time变量并在目标表上建唯一索引插入时用“插入/更新”步骤保证幂等跑出来的效率比全量同步高出一个量级。批量提交参数对内存影响也很大。表输出里的“提交大小”设置太大会导致事务长时间不提交事务日志膨胀内存里累积对象也多。我一般从 1000 开始测观察 JVM 堆占用如果堆持续升高就降下来稳了再往上加。这个参数没有标准答案和数据库负载、网络延迟都有关。5.2 字符集乱码和时区问题Kettle 6.0 的乱码问题基本都出在 JDBC URL 上。MySQL 源库或目标库的连接 URL 一定要加上参数jdbc:mysql://localhost:3306/db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai不要依赖 Kettle 界面里的“字符集”设置那只是给某些文本文件场景用的JDBC 连接层的编码由 URL 决定。如果从一个 utf8 库导到 gbk 库建议先在表输入里强制转成 Unicode再到表输出时转换编码避免中途以错误编码写入。时区问题更隐蔽。Kettle 6.0 的日期时间类型在内部有自己的存储跨时区同步时如果不指定serverTimezoneMySQL 8.x 驱动会默认取服务器时区导致时间偏差 8 小时。我碰到过一次生产库数据全部晚了 8 小时的严重事故排查了半天最后就是改 URL 加上serverTimezoneAsia/Shanghai解决的。现在只要涉及日期字段我第一反应先看连接串。5.3 Elasticsearch插件版本边界6.0的替代方案关于热搜词里那个“Pentaho 官方专门为 Kettle 9.x 和 ES 7.x/8.x 开发的新插件”我要提醒一句这个插件和你手头的 Kettle 6.0 没关系。Kettle 6.0 的插件体系停留在 5.x/6.x 时代强行把新版 elasticsearch 插件塞进去会直接报插件版本不兼容连加载都过不去。在 6.0 里写数据到 Elasticsearch最稳妥的方案是绕开插件直接用 REST Client 调 ES 的 Bulk API。Kettle 6.0 的转换流程可以这样做先通过表输入或 API 采集得到结构化数据然后用“字段选择”把字段映射好再用“JavaScript 步骤”把每行数据拼成 ES 需要的 JSON 字符串最后通过“HTTP/REST Client”发送 POST 请求到http://es-host:9200/index/_bulk。注意 Bulk API 的请求体格式比较特殊是一个 JSON 对象一行、文档一行交替排列需要在 JavaScript 步骤里自己拼接换行符。这种方案的优点是完全不依赖插件只要目标 ES 版本还支持 Bulk API就永远适用。缺点是性能比专用插件差一些但对于单次同步几万条数据的场景完全够了。如果你非要追求效率可以去找老版的elasticsearch-bulk-insert插件但版本匹配非常痛苦我试过两次都有兼容性问题后来就死心塌地改用 REST 方案了。用 Kettle 6.0 这几年我最大的体会是这个老版本其实相当稳定只要环境对了它能一直安静地跑下去。我之前有套定时同步任务跑了两年多几乎没管过。最后分享一个小技巧在做数据库迁移前先在“表输入”上右键“数据预览”看 100 行数据再往下走很多字段映射问题一眼就能看出来。等预览没问题了再把“执行”里的“每次行数”调大配合批量提交速度会有质的提升。本文还有配套的精品资源点击获取