kettle 运行时内存溢出问题调优经验总结

2 篇文章 0 订阅
2 篇文章 0 订阅

1. 技术选型:kettle + kettlepack

kettle:数据同步工具,提供丰富的组件,通过托拉拽的方式,设计一套数据抽取流程

kettlepack:负责支持远程carte服务,调度kettle的任务(转换/作业)

2. kettle 数据同步案例

① 设计start_job_i_tap_bond_info 作业,作业中添加sync_i_tap_bond_info 转换封装了具体的业务实现

 ② batch_insert 是第一次全量同步业务表数据,使用的是表输出组件,batch_update 在完成第一次同步之后增量更新,使用的是插入/更新组件

3. 运行环境

        ① kettle机器配置:单台2核2G

        ② 调度kettle任务:选用的是kettle-pack,通过调用远程的carte服务,底层其实就是发送Http请求执行kettle的作业

        kettle-pack类似于开源的xxl-job,可以配置定时策略,定时重复执行kettle的任务

4.  配置kettlepack,开启任务调度

        在kettle-pack的作业管理菜单,新增一个定时任务,选泽kettle文件,配置定时策略比如每分钟执行一次。开启后,就会每分钟执行一次

5. kettle 内存溢出问题

        第一次同步执行批量插入采用的是逻辑分页,大概执行30分钟,目标库就完成100万的数据同步。由于在开发环境,数据没有发生变动,所以在之后任务触发执行增量更新时,就是在空转,到这里没有发现什么问题。任务保持开启状态,模拟线上运行,每分钟触发一次,到凌晨大概5点钉钉出现预警:Exception in thread "sync_i_tap_bond_info - update_next_time" java.lang.OutOfMemoryError: GC overhead limit exceeded

大概意思就是说,JVM花费了98%的时间进行垃圾回收,而只得到2%可用的内存,频繁的进行内存回收(最起码已经进行了5次连续的垃圾回收),JVM就会曝出java.lang.OutOfMemoryError: GC overhead limit exceeded错误

6. 问题如何一步步定位解决的

        一开始以为是kettle-pack执行作业导致内存溢出,于是就想着绕开作业,使用转换。因为本身kettle-pack也不推荐使用作业,再加上kettle的转换相对于它的作业流程更简便。但是事实上kettle-pack在使用上有个bug:如果使用远程carte服务调度转换,并且转换里面包含另一个转换,会报:Unable to load transformation [batch_insert_i_tap_bond_info] : can't find directory xxx。kettle-pack使用的是v0.7.3版本,这个问题已经提到社区,说是后续修复更新。但是只要你的业务只要稍微复杂点,由于kettle的转换是并发执行的,如果需要控制一些步骤的顺序,就不能规避装换里面包含转换。但是经测试,使用远程carte服务调度作业没有这个问题,所以目前可以先用作业。

① 那么内存溢出的问题到底是为什么?

        通过JDK自带的工具jvisualvm(或者其它)查看运行时内存的使用情况,当时发现老年代内存使用达到98%,并且手动触发GC,老年代也几乎没有回收什么东西。当时猜测kettle 调度作业会产生一个常驻内存,同时查阅网上相关资料,猜测kettle运行本身也会占用一定的内存。

② 是不是2G内存不够,换成4G测试

        经过以上分析猜测,尝试将机器配置由2核2G换成2核4G,并且加大测试压力,配置2个任务每分钟执行一次,分别同步2张100万的数据表。监控JVM内存运行情况,发现老年代在不断增长,猜测可能是动态年龄机制导致直接挪到老年代,于是手动触发Full GC,发现老年代没有回收。最终经测试,发现4G也会撑爆。

③ 难道kettle真的有内存泄漏的重大问题?

        一方面看看Github 上有没有人提出这个问题,另一方面在想既然是开源项目,不应该存在这种严重的低级问题。

④ 最终如何找到问题原因的?

        停掉任务,观察老年代有没有释放资源,手动触发GC发现老年代内存还是几乎没有回收,但是随着时间过去,老年代释放了一些。并且通过查看日志,发现间隔性的打印如下日志内容:Cleaned up job xxx with id d837be4b-b690-47fe-a8d4-b330fe445aa0,看意思就知道在清除某个对象。于是根据" Cleaned up job "到kettle源码中定位到具体代码如下:

这段程序意思就是,后台定时任务每隔20秒扫描过期的对象,将它清除

过期的定义:任务完成或者停止,并且当前时间和任务的日志时间之差超过objectTimeout

objectTimeout:kettle 默认 1440 单位分钟,即一天

        为什么就配了一个任务,会产生大量的常驻内存。通过抓包工具(推荐Wireshark),抓取到在kettlepack触发任务执行时的http请求如下:

根据 /kettle/executeJob 定位到kettle源码中具体的那块代码,如下:

 可以看出,每次任务执行一次,就会往缓存中添加一个新的Job对象

 ⑤  最终解决方式:objectTimeout=1440 默认配的是一天,即将执行完成的Job对象保留一天时间,可以在kettle.properties中自定义该属性的值,这边改的是5分钟,即任务执行完成后5分钟就会被扫描成过期的对象,让它尽量在年轻代就被回收掉。

  • 9
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值