ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Kettle实战六问:从Spoon配置到数据同步与国产数据库连接

Kettle实战六问:从Spoon配置到数据同步与国产数据库连接 做数据开发这些年要说哪个开源工具被问得最多Kettle一定排前三。不管是临时从数据库抽个数、做张报表还是正经搭一套数据同步流程很多人第一反应就是打开Spoon拖几个步骤跑一遍。但真到部署环境、配置定时任务、接国产数据库的时候问题就一个接一个冒出来。这篇文章不打算从零抄官方文档我直接围绕下载安装、Spoon核心用法、时间参数、多表合并拆分、数据同步调度、国产数据库连接这六个最常被搜的场景把我实际用过、踩过坑的经验写出来给正在折腾Kettle的人一份能直接照着做的参考。1. 下载安装搞清版本、环境与Spoon启动的那些坑1.1 Kettle、PDI、Spoon到底是什么关系先把这个最基础但也最容易混淆的概念理顺。Kettle是这套工具的老名字后来被Pentaho收购后改叫Pentaho Data Integration简称PDI。Spoon是PDI的图形化设计器也就是你双击启动后看到的那个可以拖步骤的界面。平时说的打开Kettle或者打开Spoon本质是同一件事都是进入PDI的图形界面去设计转换Transformation和作业Job。命令行下还有两个名字要记住Pan用来执行转换Kitchen用来执行作业。后面做定时调度靠的就是这两个命令行工具而不是傻傻地开着Spoon挂机。还有一个常见的误解Kettle不只是一堆图形化步骤它的核心能力是把数据从一个地方搬到另一个地方中间做清洗、转换、合并、拆分。安装包解压即用不需要像传统软件那样跑安装向导这点对刚上手的人很友好。1.2 版本选择与JDK匹配环境错的后果是Spoon起不来我见过太多人下载了最新版结果双击Spoon.bat闪一下就没了控制台报一句UnsupportedClassVersionError然后人就懵了。这基本是JDK版本和PDI版本不匹配导致的。选版本时记住这个原则Kettle 8.x系列比较老官方建议配JDK 89.x开始很多环境用JDK 8或JDK 11都能跑10.x之后对JDK 11以上更友好。不是说越新越好而是要看你的生产服务器上装的是什么JDK以及你依赖的数据库驱动、第三方插件和哪个版本兼容。我的建议是如果你只是个人学习或者做中小项目选择一个相对稳定、能被社区资料覆盖更广的版本比如9.x系列。如果是要放到生产环境长期跑不要盲目追新尽量先用一个版本在测试环境把全流程跑通再固化下来。确认本机JDK版本的命令java -version解压完Kettle后数据集成根目录下会有Spoon.bat、Spoon.sh、Pan.bat、Kitchen.bat这些脚本。启动前先检查一下环境变量JAVA_HOME是否指向正确的JDK目录Linux下可以用echo $JAVA_HOME确认。1.3 官网下载路径与安装包形态很多人在kettle官网下载这一步就被卡住了。Kettle的官方下载页面在Pentaho官网的Data Integration产品页下入口路径一般是打开Pentaho官网找到Data Integration产品页面。页面里会有一个面向社区版的下载区域区分商业版Enterprise和社区版Community。点击社区版下载后通常会跳转到对应的开源发布平台常见的是SourceForge或GitHub Releases。下载下来的社区版是一个压缩包Windows环境是zip格式Linux环境一般用tar.gz格式。解压后目录里会有一个>-Xms1024m -Xmx2048m -XX:MaxMetaspaceSize512m这里有个经验-Xmx不是越大越好特别是不建议超过物理内存的一半。因为Kettle的转换会额外占用堆外内存给得太狠反而会导致整机卡死。调完参数后重启Spoon才会生效。2. 第一个转换从表输入到Excel输出以及时间参数藏在哪2.1 Spoon里的两个核心概念转换与作业在Spoon主界面的左侧主对象树里有两个最常用的东西转换和作业。两者千万别混。转换Transformation是最小的数据处理单元负责取数、转换、输出是一张类似流程图的网格里面每一个小方块就是一个步骤。转换里的步骤之间用Hop连线数据像水流一样从上游流向下游。转换是面向数据的它强调的是数据在每一步之间如何流转。作业Job则负责调度和编排它可以按顺序执行多个转换也可以在满足条件时做一些动作比如发送邮件、判断失败后重试。作业里连接不同作业项的是绿色或红色的跳线绿色表示成功时才走红色表示失败时走。这个机制在做定时同步时特别有用。新手最常见的错误是想在转换里做定时调度到处找地方填时间。定时调度应该在作业里做转换只负责干活不负责到点开工。2.2 一个完整的表输入到Excel输出示例我们直接做一个最小案例从数据库的一张销售表读取数据输出成Excel文件。步骤一在Spoon里新建一个转换在左侧核心对象的输入栏里找到表输入Table Input拖到画布上再在输出栏里找到Microsoft Excel 写入Excel Writer拖到表输入下方用Shift键从表输入拖一条线到Excel写入步骤建立连接。步骤二双击表输入配置数据库连接填SQL语句比如SELECT order_id, customer_name, amount, order_date FROM sales_order WHERE order_date 2024-01-01这里要注意表输入步骤里有一个替换SQL中的变量的复选框如果后面要使用变量拼接SQL必须勾上否则Kettle不会做变量替换。步骤三配置Excel写入步骤选择输出文件和Sheet名。运行这个转换就能在指定目录下生成一个包含查询结果的Excel文件。这一步跑通之后你已经掌握了Kettle最主干的用法从一个数据源读数据做简单过滤写到目标端。后面那些复杂的同步任务本质上都是在这个流程上叠加更多步骤。2.3 时间参数到底在哪里设置这个热搜点几乎每周都有人问。Kettle里时间参数其实分两种一个是你在界面右上角运行时临时传的参数另一个是数据流里自动生成的系统时间字段两者不要混为一谈。第一种在转换的空白处右键选择转换设置切到参数标签页可以新增一个参数比如叫startTime默认值填2024-01-01。保存后在表输入的SQL里就可以写SELECT * FROM sales_order WHERE order_date ${startTime}运行时有两种传参方式一是在Spoon的运行对话框里填参数值二是用命令行Pan执行时传pan.sh /fileyour_trans.ktr /param:startTime2024-06-01第二种如果你希望拿到当前系统时间比如同步时自动带一个任务执行时间字段不需要额外定义参数直接用获取系统信息Get System Info步骤它可以在数据流里产生当前日期、昨天、今天、前一天等字段。把这个步骤连到表输入后面或者表输出前面就能在目标表里写入系统时间。很多人问Kettle转换里的时间参数在哪里其实就是这两处参数定义在转换设置里引用用${参数名}时间字段来自系统信息步骤或SQL里的数据库函数。3. 拆表和合表一个表输出多个Excel、多表合并到一个表3.1 按字段分组拆成多个Excel文件的正确姿势一个表输入输出多个excel这个场景最常见的是按部门、按年月、按客户类型拆分文件。很多人第一反应是写多个表输入每个输入加一个过滤条件然后连到各自的Excel输出这种做法的缺点是表要扫很多遍业务条件一变就要改一堆步骤。更聪明的做法是只做一次表输入然后在Excel输出步骤里动态指定文件名。Microsoft Excel写入这个步骤的文件名配置框旁边有一个扩展按钮点开后可以选择从字段获取文件名也就是把数据流里的某个字段值当作文件名的一部分。比如数据流里有一个dept_name字段你可以把文件名设置成D:/output/销售数据_${dept_name}.xlsx这样Kettle在输出时遇到dept_name为华东的行就会写到销售数据_华东.xlsx遇到华南的行就写到销售数据_华南.xlsx自动完成拆分。但这里有一个特别重要的坑必须先对数据按照拆分字段排序再去动态输出。因为Kettle在处理动态文件名时是数据流里每来一行就判断一次当前文件是否变化如果数据顺序是华东、华南、华东、华南乱序交替它会在多个文件之间反复切换还可能生成大量只有几行甚至空内容的碎文件。解决方法是在表输入SQL里增加ORDER BY dept_name或是在表输入之后加一个排序记录步骤。3.2 多表合并到一个表同构表用追加异构表用关联多表合并抽到一个表听起来简单实际要分两种情况讨论因为很多人混着问。第一种两张表或多个表的字段结构完全一样比如分公司A的订单表、分公司B的订单表结构相同想纵向合并成一个总表。这种情况下最简单可靠的方式不是用Kettle步骤去拼接而是直接在表输入SQL里用UNION ALLSELECT order_id, customer_name, amount, order_date FROM beijing_order UNION ALL SELECT order_id, customer_name, amount, order_date FROM shanghai_order然后把这一路数据接到目标表输出即可。如果非要体验Kettle的图形化步骤也可以用多个表输入再依次用追加流Append Streams把多路数据串起来。需要强调的是追加流是把多路数据按顺序一条条拼接到结果集里它不会按字段去匹配所以只适合字段结构一致的表。第二种两张表结构不同但是有关联字段比如订单表和客户表要合并出订单号、客户名、订单金额这样的宽表。这样的情况最优解依旧是直接在SQL里做JOIN让数据库去处理关联而不是把数据拉到Kettle内存里。除非你真的没办法在SQL完成才用记录集连接步骤做内存JOIN。内存JOIN的痛点是必须保证输入流有序且类型匹配一旦数据量大内存压力也很明显。合并完成后目标表输出步骤需要设置提交记录数Commit Size一般批量写库时设成500或1000可以显著减少数据库事务开销。4. 数据更新同步插入/更新、增量抽取与定时调度4.1 更新同步的三种动作别只用一种步骤硬扛“Kettle数据更新同步定时任务配置”算是所有Kettle问题里含金量最高的一个。先说原理同步从目标表角度看无非是三种情况目标表没有这一行需要插入。目标表已经有这一行但某些字段变了需要更新。源表这一行已经不存在了目标表需要删除。Kettle里最常用的插入/更新Insert / Update步骤只能解决前两种。它的逻辑是按指定条件到目标表里查查到就更新指定字段查不到就插入新行。操作顺序是先配置数据库连接和目标表再指定用于判断的关键字比如订单ID最后列出哪些字段参与更新。删除动作不能靠插入更新完成要单独用删除步骤或者更稳妥一点在作业里安排一个转换专门执行DELETE FROM target_order WHERE order_id NOT IN (SELECT order_id FROM source_order)这个删除SQL要谨慎使用尤其数据量大的时候NOT IN性能很差还容易锁表。生产环境我一般建议换成LEFT JOIN加IS NULL的方式或者直接让业务方确认哪些记录需要物理删除。4.2 增量同步核心把上一次的时间动态传给SQL全量同步简单粗暴但数据量大之后每天跑全量不现实增量同步才是真正的刚需。增量同步最常见的策略是用时间字段判断比如订单表里有一个update_time字段每次同步只抽取update_time 上次同步时间的数据。在Kettle里实现这个我的标准做法是用作业串联两个转换第一个转换叫获取增量边界里面做一个表输入从源库查出当前最大时间SELECT COALESCE(MAX(update_time), 1970-01-01) AS max_time FROM source_order接着用设置变量步骤把max_time这个字段设置为Kettle变量比如变量名叫lastSyncTime。第二个转换才真正做增量抽取表输入SQL写成SELECT * FROM source_order WHERE update_time ${lastSyncTime}这里就回到前面讲的时间参数问题了。${lastSyncTime}就是你在第一个转换里动态设置出来的不需要人每天手动改。用这种作业串联的方式有一个明显好处每次同步的截止时间不是靠猜而是从源库实时查出来哪怕上次任务失败重跑边界也不会错。唯一要注意的是增量字段必须在源库建索引否则数据量大时查询会把源库拖垮。4.3 定时调度用作业内置调度还是外部定时器Kettle作业本身自带有启动作业项双击它可以在调度选项卡里设置每天、每周、每隔多少分钟执行一次。如果你只是在本地开发环境演示这样用没什么问题。但生产环境我不建议依赖它因为那意味着Spoon或Kitchen进程必须一直挂着一旦服务器重启、进程被杀任务就永远不再跑了。更可靠的做法是用操作系统的计划任务去调用Kettle命令行工具。作业用Kitchen执行转换用Pan执行Windows的任务计划程序里新建任务操作填D:\data-integration\Kitchen.bat /fileD:\etl\sync_order.kjb /levelBasic D:\etl\logs\sync_%date%.logLinux的crontab里写30 1 * * * cd /opt/data-integration ./kitchen.sh /file/opt/etl/sync_order.kjb /levelBasic /opt/etl/logs/sync_$(date \%Y\%m\%d).log 21这些命令里的/levelBasic是日志级别生产建议用Basic或Detailed别用Debug否则日志文件膨胀非常快。日志文件名带日期方便出问题时按天追溯。另一个生产经验是同步任务要设计成可重跑的。也就是说任务跑失败后人工修复数据源或目标表后直接再按一次计划任务就能恢复。如果任务里混入了大量不被设计的删除动作重跑可能产生重复数据这个需要在设计阶段想清楚。5. 支持汉高数据库吗Kettle连国产数据库的通用思路5.1 先说结论JDBC接口的数据库基本都能连热搜词里有一条kettle支持汉高数据库吗这里应该是指国产的瀚高数据库HighGo DB很多人打字写成了汉高。我理解大家的真实问题是Kettle这个出口转内销的工具会不会只支持Oracle和MySQL连不上国产数据库先说原理。Kettle本身并不直接和数据库打交道它靠的是JDBC驱动。Java世界里任何一个数据库只要厂商提供了符合JDBC规范的驱动jar包Kettle就能通过通用数据库连接或者特定的连接类型把它连起来。Oracle、MySQL、PostgreSQL是这样达梦、人大金仓、瀚高、GBase也都是同理。所以结论很简单只要瀚高数据库提供JDBC驱动Kettle就支持。这和Kettle官方有没有专门做个汉高选项没关系。5.2 国产数据库连接的具体配置以瀚高为例瀚高数据库基于PostgreSQL内核开发这意味着绝大多数情况下你可以直接用Kettle自带的PostgreSQL连接方式去连瀚高。操作步骤如下在Spoon左侧主对象树找到数据库连接新建一个连接。连接类型选择PostgreSQL。主机名填瀚高数据库所在服务器IP端口填瀚高实际端口默认端口以现场环境为准常见的是5866或5432和Oracle的1521、MySQL的3306不是一回事。数据库名、用户名、密码正常填写。点测试能通就直接用了。如果这个方法连不上就需要用通用的JDBC方式先去瀚高官方下载对应的JDBC驱动jar包放到Kettle安装目录的lib文件夹下然后重启Spoon。新建连接时选择通用数据库Generic database按照官方驱动文档填入驱动类名、连接URL、用户名和密码。一个基本一致的套路也适用于其他国产库达梦DM的驱动类一般是dm.jdbc.driver.DmDriverURL格式是jdbc:dm://IP:5236/库名。人大金仓KingbaseES也兼容PostgreSQL协议先试PostgreSQL连接方式。GBase则需要去官网找对应版本的驱动URL格式看驱动文档。5.3 连接报错怎么排查连接失败时最常见的报错就几类ClassNotFoundException说明驱动jar没放进lib目录或者放进去之后没重启Spoon。Connection refused说明网络不通、端口不对、防火墙拦截或者数据库本身没有开启远程访问。Could not load connection class这种信息大部分也是驱动类名填错了。如果URL里没写SSL相关参数PostgreSQL系数据库有时会报SSL错误在URL后面手动加?sslmodedisable通常能绕过去。还有一点容易被忽略Kettle对驱动版本很敏感。比如老版本的PostgreSQL驱动去连新版瀚高可能报协议不支持反过来新驱动连老版本PostgreSQL也可能出问题。驱动版本选择上能选与数据库同年代发布的就很合适不需要追求最新版。6. 运维中沉淀下来的几条个人经验接触Kettle这些年我觉得大部分人学这个工具卡住的往往不是步骤不会拖而是对转换和作业怎么配合、参数怎么传递、命令行怎么调度缺乏整体认识。这里分享几点我在实际运行中的体会。第一个体会是所有需要重复执行的同步任务都必须做到参数化。写死的SQL、写死的路径、写死的时间都是埋雷。把时间、表名、增量边界设计成参数之后同一个转换可以在多个环境复用调度脚本也不用每次改内容。第二个体会是生产环境日志一定要分级。Kettle的日志级别看似是个小配置其实非常关键。我见过有人一直用Debug级别跑生产任务几天下来日志文件几个G排查问题翻都翻不动。建议统一用Basic或Detailed级别并且日志按日期拆分保留最近30天即可。第三个体会是Kettle本身只是ETL编排工具它不保证数据一定不重不丢。重要的同步任务一定要设计对账逻辑比如每次同步完成后对比源表和目标表的行数、关键字段汇总值发现问题及时告警。宁可多写一个检查SQL也不要等到月底报表对不上再回头找原因。最后再补一个实用性很高的小技巧在作业的最开始放一个写日志作业项把当前执行时间、版本号、关键参数打出来。不要小看这一步很多线上问题排查第一步就是确认跑的到底是不是我改过的那个版本、用的是什么参数。有了这条日志能帮你省下大量定位时间。
返回列表