一次线上机器load负载过高报警问题排查及其后续处理

问题来源:从3.14号开始陆续收到线上一台机器的负载过高报警
问题排查 :
于是对gc、堆内存、load负载、cpu使用情况等进行了统计分析。
gc时间图标
gc时间图标
堆内存使用情况:

这里写图片描述

load负载

这里写图片描述
cpu使用率
这里写图片描述

通过以上对gc的统计,堆内存的使用情况,负载和cpu使用率的统计,我们不难发现其实在发生报警的时间范围内,不论是gc、堆内存、load负载还是cpu使用情况都是有一个上升区,然后到达峰值后下降并以此循环,所不同的是在3.14号数据量比较大最终暴露出了问题。从ygc时间曲线图看出,ygc非常不正常,在一个波动周期内ygc每次的时间会越来越长,换句话说ygc回收堆内存的速度远远没有新对象实例的速度快,也可能是堆内存中实例化的一些对象通过ygc并不能回收掉。ygc的处理时间越久对cpu的消耗越大,因为我们观察到,网卡流量、磁盘io并没有瓶颈。随后我们对线上运行的项目进行了dump堆栈信息,并是用MAT分析工具进行分析,发现内存中存在一个很可疑对象CompositeClassLoader,而这个对象的引入是在xml和Object对象进行转换的时候,引入的Xstream开源代码引入的。查看代码发现,我们每次进行一条数据的换的时候都是通过new Xstream()实例的方式,而且这部分的代码基本上都是定时任务查询出一批批的订单,然后由对象转xml发送到各外部接口,并接收外部接口的xml信息解析成Object对象,于是乎也就是说我们查到的所有对单都会在newXstream实例的时候新建一个Xstream对象,而这个对象又有什么影响呢,查看源码并且搜索文档发现:引用Xstream官网中的话The XStream instance is thread-safe. That is, once the XStream instance has been created and configured, it may be shared across multiple threads allowing objects to be serialized/deserialized concurrently也就是说,XStream是线程安全的,我们只需要为每种类型实例化一个对象即可。而我们在程序中却每次都new了一个Xstream对象。而new XStream对象时,基于JVM的类委托加载机制,该构造方法会根据类名加载类的操作,转变为new 大量new自定义的ClassLoader来加载,会产生大量ClassLoader对象以及parallelLockMap(ConcurrentHashMap)对象,导致产生大量的Segment分段锁对象,大大增加了GC Roots的数量,导致YGC中的标记时间变长。从而释了这个时间段内 YGC时间越来越长、负载越来越高的问题。

该问题解决方案
该问题其实是外部开源代码使用方式不正确,应该为每种类型实例化一个Xstream对象即可。可以单例处理,也可以静态变量初始化,当然也可以使用池化技术。

后记
在使用开源代码的时候,一定要去官方网站,后者其它一些技术网站上了解该源码的正确使用方式,避免给程序带来灾难。

以上性能问题算是解决了,但是仅仅只需要实例化一个Xstream实例,后续再只需要这个Xstream实例就可以吗?其实这里改造上线后也遇到了一个坑。请见我的下一篇文章,希望对有遇到过此问题的同学有所帮助。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值