记一次CPU飙高,频繁GC事件——大数据处理性能评估

1、背景:航班数据拆分,由原来的航班计划时间段拆分为每天的航班数据,未拆分的数据量400万,拆分为天的数据量1亿左右的数据。

2、部署到预发后进行数据拆分搬运之后的机器进程监控情况如下:

线程变化:

Old  GC情况:

进入机器内部查看:

可以看到代码中的对象FlightScheduleSplitDO类创建的实例数852315,占用的内存空间204M,此实例一直在创建没有gc掉。CPU飙高,OOM。

3、原因如下:代码中逻辑,先从旧表中拿出200个待拆分的数据,然后丢到线程池中异步去执行,因为是while(true),所以会不停的从旧表中拿待拆分的数据放入线程队列中,在线程池中的线程先将旧表中的数据拆分,然后插入到新表中,在拆分的过程中不停的创建SplitDO对象,因为线程池中的方法没有执行完,所以此对象不能快速的回收,导致该对象越来越多,还有其中的list集合与队列大对象,

解决办法:将拆分的逻辑和插入数据库的逻辑提出一个方法,同时将线程池的逻辑也放到一个方法中执行。这样方法执行完之后,其中的对象可以被提前回收掉。

其中线程池的大小是25,然后将所有的所有的未拆分的数据以1800为一组,放到list中,然后将list分为25组,每组n个1800,然后由25个线程同时执行,每个线程执行n*1800个数据,省略了线程池队列的大小,然后每个数据进行拆分的时候都是方法去执行,方法执行结束后所创建的实例在新生代中被回收。最终执行的时间由10个小时缩短为1个小时。

总结:

1、通过top查看CPU情况,如果CPU比较高,则通过top -Hp <pid>命令查看当前进程的各个线程运行情况,找到占用CPU的线程PID,然后通过jstack命令  jstack 44 | grep  "0x1b6"  打印pid为16进制的1b6的线程堆栈信息,查看该线程主要进行的工作。

2、如果是正常的用户线程,通过堆栈信息可以找到具体在代码的哪一行消耗CPU。

3、如果是VM Thread,则通过jstat命令查看gc情况,通过jmap查看哪些对象比较消耗内存。以上的情况就是有大对象消耗内存。

4、比较耗时的代码,可以加大请求量,查找多个线程同时堵塞的代码行数。

5、某个线程处于waiting状态时间长,可以查看20S-30S的线程堆栈信息,如果一个用户线程一直是waiting状态则需要排查。

6、死锁,jstack命令可以直接打印死锁的线程信息。

后面的三种情况主要针对导致功能缓慢的情况排查。

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值