kettle实操笔记
kettle是非常老牌的etl工具了,最早可以追溯到我还未工作的时候,但是不得不说,这个工具非常好用,而且学习成本也比较低,所以现在很多实际的项目中仍然有不小的使用率,也正是因为如此,我就把入门级别的一个实操笔记分享给大家,有很多深入的使用大家还是得到网上去检索,比如集群、比如接口等等。
基本操作
几个基础概念
etl
ETL,是英文Extract-Transform-Load的缩写,用来描述将数据从来源端经过抽取(extract)、转换(transform)、加载(load)至目的端的过程。ETL一词较常用在数据仓库,但其对象并不限于数据仓库。
ETL是将业务系统的数据经过抽取、清洗转换之后加载到数据仓库的过程,目的是将企业中的分散、零乱、标准不统一的数据整合到一起,为企业的决策提供分析依据, ETL是BI(商业智能)项目重要的一个环节
简单一句话就是etl就是数据交换的工具。可以提供跨数据库数据交换,支持定时任务,支持多种数据格式,支持数据治理等等。
转换
转换是kettle中的一个对象,是数据交换的基础对象。

输入对象
主要是数据源的输入对象,例如:表输入。

几点注意
表输入对象中,需要选择数据连接 sql尽量在plsql中先测试并编辑好,尽量不要使用获取sql 增量交换尽量限制记录数,如果记录数设置为0,则是将sql查出的全部结果集作为输入

输出对象
作为数据交换后的数据输出,例如:表输出。

几点注意
表输出中需要选择数据库连接,即数据最终要推送的目标数据源 目标模式:在oracle作为表输出的数据源时,需要明确目标模式 目标表:对应输出表的表名 提交记录数量:最大作为一批次向目标数据源commit的数据记录限制,需要根据实际情况设置,比如如果单批次10000数据的时间必须一致(时间戳模式),那么此处应设置为10000 指定数据字段:需要做字段映射关系设置时应选择(一般都需要) 获取字段:根据表输入和表输出的字段生成初始映射关系 输入字段映射:需要对字段映射关系做调整时使用,比如部分字段不推送


脚本对象
可以直接在其中进行脚本编写,以实现满足业务需要的数据处理,如:sql脚本,可以直接在其中编写标准的sql。

转换对象
需要对输入的数据进行处理,比如去重,值映射等。

数据连接

几点注意:
当数据库连接是oracle,并且版本大于12时,需要选择oracle RDB方式,并且对应的数据库连接信息需要在kettle的jdbc配置文件(kettledata-integrationsimple-jndijdbc.properties)中进行配置,而在设置数据库连接时只需要输入对应定义的JNDI名称即可


作业
作业是对转换的组合、调度,在转换中是没有严格意义的先后顺序的,而作业中的每一个任务环节都是有顺序的。
比如,在转换中,表输入1万条数据,而表输出是按照1千条记录条件,那么在提交了1千条之后,表输出之后的任务也会同步开始,而不是等1万条都输出完成

如上图中,作业的执行顺序是start->truncateXXX->同步->转换->成功,任何一个环节异常都会导致作业失败。
作业中的常用对象包括START(标记任务开始),脚本对象(与转换的脚本对象类似),转换对象(可以选择定义好的转换对象),成功(标记正常结束)
START
可以定义任务的执行周期,也就是起到定时器的作用。可以按照秒、分钟、小时、天、周、月的周期进行配置。

启动
选择日志类型,在测试时可以选择基本日志,在正常启用后建议把日志设置为错误日志级别,也就是有异常时才会记录,主要可以大大提升kettle的运行稳定性,因为日志会在控制台输出,而长时间的输出会导致内存溢出等异常。

进阶场景实操
以上都是入门的操作,也很简单,但是实际我们在数据处理和交换时往往会遇到比较复杂的情况,因此根据场景进行组合、定制才是关键。
首先要说的一点是,kettle的目的是进行数据交换,因此我们在开始定制前应该先把数据交换的逻辑整理清楚,然后在按照逻辑去定制,这样才能保证没有问题,也就是说kettle使用是需要一定的设计能力的。
另外一点需要说的是,kettle在做数据交换时定制很方便,但是如何提高kettle的稳定性和交换性能是需要去注意的。
场景一 增量交换
增量交换是经常会遇到的一个场景,应该说是基础中的基础场景,大部分的数据交换都是需要满足长期的增量交换的,复杂的交换任务其实都是基于增量交换的逻辑去处理的。
增量交换常用的几种方式,时间戳、标记位、推送记录。个人比较喜欢用的是推送记录方式
时间戳方式
首先要在待交换的数据中统一时间戳数据项,同时要将每次交换完成的最大时间戳记录,要保证在每次抽取时将满足的数据全部抽取
此种方式存在几个问题:
-
需要限制每次的数据量大小,因为数据量过大影响交换效率和数据准确性,对于无法保证某一时间交换数据量的情况下,不建议使用该方式。 -
可能存在数据并发时,导致漏数据的情况
标记位
标记位是指在待交换数据项中,其中一项作为标记为数据项,在交换完成时需要修改该数据项为已交换,而每次抽取时只读取未标记的数据
此种方式存在几个问题:
-
需要修改数据源的数据,因此会大大降低交换的效率。对于数据量较大的情况,不建议采用。
推送记录
顾名思义,就是将已推送的数据进行记录,再次推送时只推送不在记录中的数据。
此种方式存在几个问题:
-
需要额外创建交换记录表,而且需要包含待交换数据的主键数据项 -
历史交换记录随着交换的增加而剧增,后期会影响交换性能(优化方式:需要定期做历史数据备份,以此来优化交换效率)
例子就是一个推送记录的方式进行的数据交换

上图的转换定义了在数据集输入(oracle)后,首先为数据集生成UUID,然后插入记录表,最后交换至mysql的目标库。
场景二 内部循环
比如这个场景,我们需要删除1千万的数据,简单的任务,我们可以直接定制一个脚本,在其中写入需要删除数据的逻辑即可
但是实际生产环境中,删除1千万的数据会需要很长时间,如果是一个并发读写的数据表时间就会更长,很有可能最后导致删除失败任务卡死,或者表被锁死。
解决思路
一次性删除1千万很慢,但是删除几万数据还是很快的,所以需要将1千万的数据分批次删除,这个时候就需要去使用内部循环,在目标数据未删除之前,需要一直重复运行删除操作。

详细任务配置
basic_num是计算待删除数量的转换,将数量作为参数传递给下一步骤,下一步骤采用验证组件



设置在父作业中变量生效,即可将变量的值传给作业,进而在下一步骤的组件中获取到

场景三 kettle的函数
有时候我们需要使用kettle给我们提供的内置函数带来应用中的一些方便。比如日期函数
如下的一个应用中,我们需要获取执行任务的当前时间,以避免与数据库的时间不一致导致与预期的时间影响不一致。

具体看下该转换

获取系统信息

有很多的系统函数,可以自行去尝试一下,这里获取系统日期和时间,并把它赋值给DQ_DATE参数,再看下格式化的js代码
//Script here
Date.prototype.Format = function (fmt) { //author: meizz
var o = {
"M+": this.getMonth() + 1, //月份
"d+": this.getDate(), //日
"h+": this.getHours(), //小时
"m+": this.getMinutes(), //分
"s+": this.getSeconds(), //秒
"q+": Math.floor((this.getMonth() + 3) / 3), //季度
"S": this.getMilliseconds() //毫秒
};
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
for (var k in o)
if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
return fmt;
}
var dtNew=new Date(new Date().getTime()).Format("yyyy/MM/dd/ hh:mm:ss");
设置变量刚才已经介绍过了,同样是设置在父作业中生效

在父作业中,需要设置下一步骤的转换参数信息

在该转换内部需要设置读取变量

在转换中的步骤中可以直接使用该变量

补充:
格式化的另一种方式,比js代码更方便,就是使用字段选择组件,在其中设置格式化即可。

kettle的集群
这部分大家在充分掌握以上内容之后,再去研究。kettle的集群很厉害
另外,还有其他的一些比较新的工作,比如DataX,这个也是性能很好的工具,推荐大家去掌握。
注意点:
对数据库比较熟悉的同学,尽量利用数据库的能力来满足交换,这样可以在对kettle没有那么熟的时候满足大部分的交换场景,因为kettle作为etl工具,他对交换的最大瓶颈一定来自于数据库的IO能力。对于初学者,我也建议先熟悉数据库相关的技术知识
常见问题
-
尽量不要使用插入更新作为输出,因为效率太低,尽量使用表输出,而且输出的表尽量是空表,这样效率最高 -
有时候会出现kettle工具内存不够报错的情况,可以在启动的脚本中设置大一点的Xms(JVM的初始堆内存)和Xmx(JVM的最大堆内存),java.lang.OutOfMemory错误就是Xmx的值过低导致,但是一般将这两个值设置为一样大,也就是物理内存的1/4,这么做是避免GC之后调整堆大小;另外MaxPermSize是最大非堆内存的,这个值一般为物理内存的1/4,如果过小会报内存溢出(java.lang.OutOfMemoryError: PermGen space),但是要注意Xmx和MaxPermSize的总和不能超过物理内存,否则无法启动,这些其实是JVM的知识,对于java的应用程序都是通用的。
原文始发于微信公众号(云户):kettle实操笔记
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/35239.html