Kettle data-integration.zip 实战:ETL 数据同步与避坑指南
简介这份># 在 Spoon.bat 或 spoon.sh 中找到类似行按需修改 # Windows: set PENTAHO_DI_JAVA_OPTIONS-Xms512m -Xmx4096m -XX:MaxPermSize256m # Linux: export PENTAHO_DI_JAVA_OPTIONS-Xms512m -Xmx4096m逻辑说明-Xms是初始堆-Xmx是最大堆设成一样可以避免运行中反复扩堆。-XX:MaxPermSize在 Java 8 以后已经废弃如果脚本里还留着启动时会打印警告但不影响运行可以删掉。参数改完要重启 Spoon 才生效。如果你在 Linux 服务器上跑 Kitchen 定时任务同样要改kitchen.sh里的这行否则凌晨跑大表时进程被 kill 掉日志里只会留一句java.lang.OutOfMemoryError排查起来很费时间。2.3 数据库驱动放置与连接测试把驱动 jar 放进lib后新建“数据库连接”时选择类型填主机、端口、库名、用户名密码。这里有个细节Kettle 的连接测试按钮只验证网络和账号不验证字符集。如果源库是utf8mb4目标库是latin1测试能过但抽数据时中文会变问号。我一般会在连接的高级选项里手动加characterEncodingutf8或useUnicodetruecharacterEncodingutf8。另外Oracle 驱动要选ojdbc8.jar对应 JDK8ojdbc10.jar对应 JDK10 以上放错版本会报No suitable driver found。测试连接通过后建议在“选项”里把useSSLfalse加上避免 MySQL 8 默认 SSL 导致的握手失败。3. 用 Spoon 跑通第一个转换从 CSV 到 MySQL 的完整步骤3.1 新建转换与核心组件选型打开 Spoon新建“转换”左侧核心对象里拖入“CSV 输入”和“表输出”。为什么不用“文本文件输入”因为 CSV 输入对分隔符、引号、编码的处理更直观适合快速验证。CSV 输入里要设置文件名、分隔符逗号或制表符、编码UTF-8 或 GBK。如果文件有表头勾选“头部行存在”然后点“获取字段”让 Kettle 自动识别列名和类型。这里容易踩的坑是自动识别的日期列可能被当成 String后续插入 MySQL 的 datetime 字段会报Incorrect datetime value。解决办法是在“获取字段”后手动把类型改成 Date并指定格式如yyyy-MM-dd。表输出里选择目标连接和表名勾选“指定数据库字段”把流字段和表字段一一映射。如果目标表不存在可以勾选“创建表”让 Kettle 根据流字段生成 DDL但生产环境不建议这么做因为生成的字段类型往往不是你想要的。3.2 字段映射与类型转换的实操下面是一个典型的字段映射配置片段用 XML 表示转换步骤的一部分Kettle 的.ktr文件本质就是 XML。你不需要手写但看懂它有助于排查问题!-- 转换步骤CSV输入 -- step nameCSV输入/name typeCSVInput/type filename${INPUT_FILE}/filename delimiter,/delimiter encodingUTF-8/encoding fields field nameid/name typeInteger/type /field field nameorder_date/name typeDate/type formatyyyy-MM-dd/format /field /fields /step逻辑说明${INPUT_FILE}是命名参数可以在启动时用-param:INPUT_FILE/data/order.csv传入方便同一转换处理不同文件。type决定了解析方式Integer 会尝试把字符串转成整数失败则置空。Date 类型必须配format否则按默认区域格式解析容易出错。参数说明delimiter只写一个字符如果是制表符就写\tencoding要和文件实际编码一致用file -i命令可以查看 Linux 下文件编码。映射完成后点“预览”看前 100 行确认没有乱码和类型错误再执行。3.3 执行、日志与性能初探点运行按钮Spoon 会弹出执行窗口显示每一步的读写行数、耗时。如果某一步骤变红点“日志”看堆栈。常见错误有目标表字段长度不够导致Data too long主键冲突导致Duplicate entry。性能方面默认的提交记录数是 1000可以在表输出里改成 5000 或 10000减少事务提交次数。但注意如果转换中途失败已提交的数据不会回滚所以增量同步要配合“更新/插入”组件或先清空临时表。我一般会在表输出前加一个“排序记录”按主键排序再配合“合并记录”做增量但那是更复杂的场景新手先把全量跑通再说。4. 避坑与排查Kettle 开发中五个血泪经验4.1 中文乱码现象、原因与解决现象CSV 里的中文抽到 MySQL 变成???或者从 Oracle 抽到 Hive 变成乱码。原因源文件编码、Kettle 转换编码、目标库字符集三者不一致。解决第一步用file -i确认源文件编码第二步在 CSV 输入里显式设置编码第三步在数据库连接的高级选项里加characterEncodingutf8第四步确认目标表建表时是utf8mb4。如果还不行在“表输出”前加一个“字段选择”组件把 String 字段的 Trim 类型设为both去掉首尾空格和不可见字符。4.2 日期格式翻车从 String 到 Date 的转换现象源数据日期是2024/01/15目标字段是datetime插入时报Incorrect datetime value。原因Kettle 自动识别为 String直接拼 SQL 时格式不匹配。解决在 CSV 输入或“字段选择”里把该字段类型改为 Date格式填yyyy/MM/dd。如果源数据有多种格式先用“公式”组件或“JavaScript 代码”组件统一成yyyy-MM-dd再转 Date。注意JavaScript 组件里用str2date函数要小心时区服务器时区不对会导致日期差一天。4.3 内存溢出大表排序与聚合的应对现象转换跑到“排序记录”或“分组”时卡住日志报OutOfMemoryError: Java heap space。原因这些步骤会把所有数据加载到内存。解决调大-Xmx只是缓兵之计根本办法是改用数据库端的ORDER BY和GROUP BY或者用“阻塞数据直到步骤完成”配合分批。我一般会把大表拆成按天或按 ID 区间的小批次用 Kitchen 循环调用。如果非要在 Kettle 里排序把“排序记录”的“临时文件目录”设到一个大容量磁盘并勾选“压缩临时文件”。4.4 驱动版本不匹配No suitable driver found现象连接测试报No suitable driver found for jdbc:mysql://...。原因驱动 jar 没放对位置或者版本与 JDK 不兼容。解决确认 jar 在lib目录下不是libext或plugins。MySQL 8 用mysql-connector-j-8.0.33.jarOracle 用ojdbc8.jar。如果还报错检查spoon.bat里的 classpath 是否包含lib下所有 jar。有时候杀毒软件会锁定 jar 文件导致加载失败临时关闭杀毒软件试试。4.5 定时任务不执行Kitchen 与 Carte 的权限问题现象Linux 下用 crontab 调kitchen.sh跑转换手动执行正常定时执行没反应。原因crontab 的环境变量和登录 shell 不同JAVA_HOME 没设置或者脚本没有执行权限。解决在 crontab 里显式设置JAVA_HOME和PATH或者写一个包装脚本run.sh在里面source /etc/profile后再调kitchen.sh。另外kitchen.sh要有x权限转换文件路径用绝对路径。日志重定向到文件方便排查。5. 进阶技巧用参数和 Carte 把转换变成可调度服务5.1 命名参数让同一转换处理不同数据源在转换里点“转换属性”-“参数”添加INPUT_FILE、OUTPUT_TABLE等。然后在步骤里用${INPUT_FILE}引用。执行时用kitchen.sh -param:INPUT_FILE/data/2024-01-15.csv -param:OUTPUT_TABLEorder_20240115。这样一份.ktr可以每天处理不同文件不用改代码。参数还可以设默认值避免漏传导致空指针。我习惯把数据库连接也参数化比如${DB_HOST}、${DB_USER}这样开发、测试、生产环境用同一套转换只换参数文件。5.2 Carte 服务与远程执行Carte 是 Kettle 自带的轻量 HTTP 服务启动后可以接收远程执行请求。在># 触发 Carte 上已发布的转换 curl -u cluster:cluster http://192.168.1.100:8080/kettle/runTrans/?transorder_syncparam:INPUT_FILE/data/order.csv逻辑说明runTrans是执行转换的接口trans参数是转换在 Carte 上的名称param:前缀传命名参数。返回结果是 XML 格式包含执行 ID 和状态。参数说明Carte 默认端口 8080账号密码在pwd/kettle.pwd文件里改。注意Carte 不适合高并发它只是轻量调度生产环境通常用 Kitchen 配合 crontab 或 Airflow 调用。5.3 验证转换正确性的三个习惯第一每次改完转换先用“预览”看每个步骤的输出不要直接跑全量。第二在目标表里加一个etl_load_time字段默认CURRENT_TIMESTAMP跑完查最新时间确认数据到了。第三用SELECT COUNT(*)对比源表和目标表行数如果不等检查是否有主键冲突被忽略。我还会在转换最后加一个“写日志”组件把处理行数写到一张日志表方便追溯。从那以后我每次上线新转换都强制走一遍“预览-小批量-全量-对数”的流程再也没出现过半夜被叫起来修数据的情况。希望帮到你。本文还有配套的精品资源点击获取