起因
基于一些原因,需要将kettle6.1升级到新版的kettle8.2。升级后发现kettle8每隔几天出现
GC overhead limit exceeded 或者 OutOfMemoryError:Java heap space;
一开始猜测kettle8为了提高性能,而牺牲更多的堆内存,便从开始的Xmx2048m 增加到 Xmx4096m.
可是没过几天还是一样出现问题,又从4096m增加到6144m.
问题依旧得不到解决.
通过排查日志发现内存溢出的问题发现: 定时重复执行的作业出现数据库连接不上,
导致好几天的作业一直都在报错数据库连接拒绝,一直到内存溢出,kettle奔溃.
排查发现,只要作业是正常执行,kettle8.2就不会出现内存溢出的问题.
但是只要有作业一直报异常,那么只要1-2天(也可能更短,看作业执行频率),
kettle8.2就会内存溢出挂掉,
kettle6.1不会出现此种情况.
场景重现
测试环境部署kettle8.2,模拟重现.
在kettle8.2 启动脚本增加
-Dcom.sun.management.jmxremote.port=9008 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false
本地jconsole可以远程实时监控kettle运行时的内存与线程情况
增加
-Xdebug -Xrunjdwp:transport=dt_socket,address=5005,server=y,suspend=n
本地idea可以远程debug
在idea中git clone kettle8.2的源码.
往kettle上发了10个作业,每隔5秒重复执行.其中9个作业是正常执行的,
1个作业连接一个不存在的数据库,会一直报连接拒绝错误
jconsole监控如下图
红框时间区间是该错误job停用的时间段,期间内存能维持稳定。
在测试服务器上使用命令jmap -heap,发现老年代内存居高不下,无法回收。
排查
再使用命令jmap -histo:live >> a.log(JVM会先触发gc)排查哪些对象没有被回收
327 83712 org.pentaho.di.trans.Trans
327 20928 org.pentaho.di.trans.steps.selectvalues.SelectValuesMeta
327 20928 org.pentaho.di.trans.steps.tableinput.TableInputMeta
327 31392 org.pentaho.di.trans.steps.insertupdate.InsertUpdateMeta
866 27712 org.pentaho.di.trans.TransHopMeta
基本上可以断定是每次错误执行的作业中的转换(trans)没有被GC回收。
但是仅根据堆内存中的对象数量无法判断是哪里还在引用这些对象。
使用命令 jmap -dump:live,format=b,file=./dump.dat 生成内存镜像
使用命令 jhat -J-Xmx1024M ./dump.dat (jdk自带分析工具)
执行后等待console 中输入start HTTP server on port 7000 即可使用浏览器访问 IP:7000
随机查看了几个引用trans对象的对象,看不出什么
kettle的对象互相引用太多太复杂,jhat这个工具很难直观找到最上层的引用对象
下载dump文件到本机,使用eclipse的插件 memory anaylize 分析dump
如下图
在树形图上容易trans对象没有被回收是因为被最上层的HashMap引用
在树形图中找到容易定位问题代码对象是
org.pentaho.osgi.blueprint.collection.utils.ServiceMap
查看源码,猜测作业执行异常的情况,没有执行itemRemoved方法,导致本该被回收的对象在内存越积越多
在源码中新增、修改两个方法打上断点,开启远程debug 如下图
调试一个正常的作业和错误的作业,发现确实如推测的,执行报错的作业最终没有执行itemRemoved.
调试过程跳过
定位具体代码 org.pentaho.di.trans.Trans
public void execute( String[] arguments ) throws KettleException { prepareExecution( arguments ); startThreads(); }
正常执行的job 会在 prepareExecution方法中的transMeta.setEmbeddedMetastoreProviderKey(....)
中调用serviceMap的itemAdded()
并在startThreads()方法中的transMeta.disposeEmbeddedMetastoreProvider()中
调用serviceMap的itemRemoved()
异常的job会在prepareExecution方法中初始化step时抛出数据库连接异常,导致后续不会进入到startThreads().
这下内存溢出的问题明确了,稍微修改源码,打包替换原先的kettle-engine.8.2.0.jar.
至此,kettle8.2内存泄漏问题彻底解决
相关推荐
kettle内存溢出(Java heap space)以及解决方法
我自己编写的KETTLE6.1与KETTLE7.1版本之间的差距比较
kettle合并记录处理同表数据更新等操作.doc
NULL 博文链接:https://qq85609655.iteye.com/blog/2173882
统计重复数据的个数,及相同记录都有哪些,如有不懂的地方可随时联系
针对于数据加工kettle如何去进行二次开发,里面包含详细的描述
ETL之kettle 增量更新并标识删除的记录 不删除原始数据
jdk8-251 kettle9.2使用jdk版本
etl工具-kettle6.0
Kettle实现步骤循环执行 Blog:http://blog.csdn.net/jdk2006/article/details/13019093
内容概要:ETL之kettle包含26张PPT,kettle安装、使用、如何连接等,使用PDI9.2演示、什么是ETL、什么是Kettle、kettle安装、kettle目录结构、转换和作业、kettle操作、数据库连接、注意事项。 适合人群:具备一定...
适配了达梦数据库的kettle核心代码。
kETTLE版本:8.2.0 jdk配套的,ojdbc8配套, 全是64位的。 百度网盘下载地址
这个kettle 的插件,它可以从一个或多个 PDF 文件中抽取文本内容,抽取后的文本一页作为一行记录,便于后续处理,如写入数据库等等。 帮助手册 http://www.xgndata.com/resources/kettle/PFR_UserGuide_zh_CN.pdf ...
KETTLE表输入变量执行每一行,ORACLE数据库,scott用户,密码oracle
Java获取kettle的结果集
《ETL数据整合与处理(Kettle)》教学教案 —03记录处理.pdf《ETL数据整合与处理(Kettle)》教学教案 —03记录处理.pdf《ETL数据整合与处理(Kettle)》教学教案 —03记录处理.pdf《ETL数据整合与处理(Kettle)》教学教案 ...
Kettle 样式 很全的的开发手册 主页 各种图片位置以及加载页 log 文字 等等
kettle设置循环变量,控制循环作业;kettle设置循环变量,控制循环作业.
kettle执行转换每一行数据,数据库连接JDBC,oracle数据库,scott用户,密码oracle