一种优化Kettle转换性能的通用方法


 

1、问题背景算法

转换和做业是Kettle的两支利剑。其中,转换采用多线程并发运行架构,做业采用递归顺序执行架构。所以,在增长CPU、内存等硬件资源的状况下,Kettle转换只需修改配置,便可充分利用基础设施能力,提升执行效率。转换的这种垂直扩展能力,使其成为实现ETL功能的必备工具,也是性能优化的核心。数据库

固然,性能优化是一个系统工程,不只涉及工具自己的优化,更涉及到ETL工具以外的诸多因素。好比,ETL要读取数据库,那么目标DMBS的性能、SQL语句、网络等相关因素都影响到执行效率。Kettle的中文意思为水壶,意即经过这把“水壶”,把上游产生的“水”(数据)顺利输送到下游各部门。想要让整个输送过程实现效率最高,取决于三个因素:上游来水渠道、水壶的大小与数量、下游输水渠道。编程

本文在假设第1、第三个因素已经达到最优的前提下,讨论第二个因素如何优化。即在外部环境因素不变、内部转换不变时,如何定位到性能瓶颈步骤,并经过垂直扩展进行有针对性、实效性的优化。文章最后还简要介绍了自定义优化插件的编程思路。数组


2、工具局限性能优化

Kettle工具自己具有性能监测手段。设计阶段经常使用的Spoon工具中,转换执行以后,窗口底部执行结果中有一个步骤度量标签页(以下图1所示)。微信

图1网络

                           

从步骤度量中,能够看到每一个步骤的执行时间以及速度。在生产环境中,经过Pan或者Kitchen的执行日志,也可以看到读、写行数和速度。那么,是否是速度慢的步骤就是性能瓶颈?或者执行时间最长的就是卡的步骤呢?下面经过实例来分析。多线程

图1中的转换,共包括42个步骤。在测试机器上,经过Spoon中调试执行共需3分4秒,各步骤的性能度量结果图2所示。架构

从图2中能够看出,执行时间长、执行速度慢的步骤都集中在黄色区域,即步骤C01~C15和D00~D07,每一个步骤的执行时间大概是3分1秒。那么,性能瓶颈是否就在这些步骤中呢?并发

答案是非也!

经过目测Spoon调测窗口(详见图1中虚线框步骤)的运行状态,咱们能够看到,C01前的步骤几乎都在5秒内完成,而C01后的步骤,因为都在等C01的输出,因此执行时间随之变长,执行速度几乎都在1条记录/秒。所以,本转换的性能瓶颈在步骤C01,跟其余步骤无关(固然这种目测方法不适合用于生产环境)。

图2

 

3、解决办法

一、原理探究

致使这种误判现象背后的缘由到底是什么呢?

咱们分析发现,Kettle列出的每一个步骤的执行时间,是经过步骤完成时间减去步骤开始时间而得出的时间间隔(参照图3中org.pentaho.di.trans.step.BaseStep源码)。所以,即便步骤没有作具体的事情,只是在等待输入行,但因为步骤并无执行完毕,因此等待时间也包含在执行时间中。这是致使误判的根本缘由。

图3

经过JDK工具JavaVirtualVM监测各线程执行状态,也能够证明这一点。图4为转换执行过程当中的一个截图。能够看出,Kettle为每个转换都至少启动了一个线程,线程的命名规则为:

转换名称 – 步骤名称

本例转换名称为KettleSample004,因此步骤C01所在线程名称就为“KettleSample004– C01”。图4中绿色部分表明线程处在工做状态,橙色部分表明等待执行状态。截图时刻(15:51:4015:52:00),步骤C01一直处在工做状态,而C02~C15基本上都处在等待状态(只有C02存在小段工做时间)。

图4

所以,解决问题的关键在于,须要一个程序来统计步骤的实际工做时间,实际工做时间长的步骤,能够断定为转换性能瓶颈。图5为在另一台测试机器上,运行一样转换获得的实际工做时间数据(去掉了一些时间很是短的步骤),左侧为各步骤实际工做时间表,右侧为时间数据散点图。因为C01实际工做时间与其余步骤相比悬殊太大,为了更容易分类,右侧下半部分绘制了排除C01时间数据以外的散点图。从图5中的数据能够明显看出转换的性能瓶颈步骤,也能够根据散点图按照各步骤执行时间分为几种不一样类别,分类进行优化。

图5


二、手工解决办法

第一步:分组。

根据散点图的分析结果,咱们能够按照实际工做时间的长短,将步骤分为5个组(以下表1所示)。实际工做时间在100-400毫秒之间的步骤纳入#1组;实际工做时间在2100~6800毫秒之间的步骤纳入#2组;实际工做时间在7800~12000毫秒之间的步骤纳入#3组;实际工做时间最高的C01单独纳入#4组;其余步骤纳入#5组。

表1

第二步:定义命名参数。

在Spoon中双击转换,在转换属性对话框中添加4个命名参数,并设置默认值。表1中的其余步骤分组#5无需单独定义参数,由于这些步骤的复制数量能够保持默认值1不变。具体设置如图6所示。

图6

第三步:设置步骤。

根据表1的分组结果,设置每个步骤的复制数量,以利用Kettle的垂直扩展能力。具体操做是在每个步骤上点击右键,选择“改变开始复制的数量…”菜单,并按住Ctrl+Alt+空格键,在下拉框中选择对应分组的命名参数便可。注意,某些步骤可能不容许改变复制数量。若是这些步骤对性能调优很是重要,咱们能够在步骤前加一个空操做步骤,再进行设置;若是不重要,忽略便可。配置后的结果以下图7所示:

图7

第四步:运行调优。

若是咱们单纯把线程数量无限增大,因为建立线程、线程上下文切换等其余资源的消耗,可能带来执行速度不升反降。所以,不能简单地按照实际工做时间比例来调整复制数量。例如#4组的实际工做时间是#3组的40倍以上。按此比例,#3的值若是设置为8,那么#4的值应该设置为320,这显然不是一个合理的设置。因此在环境不变的状况下,如何获得最优的复制数量,是一个有挑战性的问题。本文仅讨论依据经验经过不一样设置的实际执行效果,来找到局部最优解的方法。其余方法将在另外的文章中进行讨论

经过Pan命令,能够设置不一样的参数来执行一样的任务,经过总体运行时间,找到一个较好的参数组合。具体命令示例以下(Windows环境):

Pan.bat "/file:D:\KettleSample004.ktr"  "/param:#2=1""/param:#3=1" "/param:#4=1"

在测试机器上,不一样参数组合的执行结果以下表2所示:

表2

从4次实验的结果看,选择2,3,8,10的参数值组合,执行时间为16秒,获得局部最优解。


三、使用插件

比手工解决更快捷的方法是利用插件,收集各步骤的运行结果,并自动分组、定义各分组相关步骤的命名参数。特别是在步骤相对较多的状况下,能够极大提升工做效率。下面简要介绍插件的用法。

第一步:打开已经定义好的转换,在左侧核心对象树中选择Kettle博士分类下的复制优化步骤,拖动放到转换中的任意位置。

第二步:双击复制优化步骤,在弹出的对话框中选择清空全部复制,并点击肯定。这样,转换中全部已经设置复制数量的信息都将清空,以确保获取真实的性能监测数据。以下图8所示。

图8

第三步:双击复制优化步骤,在弹出的对话框中输入分组的数量(默认是7个分组),勾选自动建立参数,并点击肯定。以下图9所示。

图9

第四步:运行转换。能够在Spoon中或者生产环境命令行中执行。执行后,能够在日志中看到分组的结果、每个步骤的实际工做时间等信息,并自动建立相关命名参数,设置到转换每个相应的步骤中(若是在Spoon中运行,须要从新打开转换文件)。下图10为在Spoon中执行的结果分析信息,图11为自动建立的命名参数以及步骤设置结果。

图10

图11

4、插件编程要点

下面来介绍插件编程的主要代码,插件中基于实际工做时间进行聚类的算法不在本文讨论之列。读者能够参照其余数据挖掘文章,找到关于聚类的算法。

首先须要了解的背景知识是,Java线程包含6种状态(NEW RUNNABLE BLOCKED WAITING TIMED_WAITING TERMINATED),对于优化需求而言,只需统计Kettle转换步骤线程的RUNNABLE状态时间,而后排序输出便可。主要代码解释以下:

一、查找转换的全部步骤

用到类org.pentaho.di.trans.Trans的主要方法:

  • publicList<StepMetaDataCombi> getSteps()

能够获得转换的全部步骤列表。列表中每一个元素都是StepMetaDataCombi类的实例。而StepMetaDataCombi类有一个公有属性stepname表明步骤名称。

  • publicString getName()

能够获得转换名称。

如前所述,获得了转换名称和步骤名称,Kettle步骤执行线程的名称便可肯定。

二、查找全部线程

查找全部线程的方法代码以下:

public Thread[] findAllThreads() {

  if(topGroup == null) {

    ThreadGroupgroup = Thread.currentThread().getThreadGroup();

    topGroup= group;

    while(group != null) {

      topGroup= group;

      group= group.getParent();

    }

  }

  intestimatedSize = topGroup.activeCount() * 2;

  Thread[]actualContainer = new Thread[estimatedSize];

  intactualSize = topGroup.enumerate(actualContainer);

  Thread[]threads = new Thread[actualSize];

  System.arraycopy(actualContainer,0, threads, 0, actualSize);

  returnthreads;

}

三、时间统计

启动一个后台线程,固定间隔时间查看各线程状态,若是为RUNNABLE状态,则累计时间。一直到转换执行完毕或者中止时,时间统计能够中止,排序输出统计结果后,线程运行结束。判断转换是否执行完毕,能够调用上述Trans类的isFinished方法;判断线程是否中止,能够调用其isStopped方法。

四、复制次数设置

添加命名参数,能够调用TransMeta类的addParameterDefinition方法。设置复制数量,能够调用StepMeta类的setCopiesString方法。


5、总结

本文介绍了经过对Kettle垂直扩展参数的优化,提升转换执行性能的方法。同时也把编程相关API要点逐一阐述。全部实际工做中的转换优化问题,都可参考。因为每个转换步骤优化的方法不尽相同,因此未讨论单个步骤的优化问题。

如需原始转换及演示数据文件,请联系微信号carol_sxh获取,添加好友时请注明所需文件名(示例转换文件KettleSample004.7z(免费);插件文件kettle-doctor-plugin.7z(付费))。

注意:因为插件只在Kettle6~8版本上进行过验证,其余版本未经严格测试,使用前务必作好备份!

 

【注意】本公众号所发文章皆为原创,如转载请注明出处及做者。





 


本文分享自微信公众号 - Kettle博士(gh_f656c3d7ba54)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索