记一次JVM生产OOM及后续调优

2020年03月18日,开年第一个生产事故发送在我的项目组o(╥﹏╥)o

事故发生

在下午2点40时,收到了第一个客户投诉,紧接着收到了第二个、第三个。
并且不断的有各业务系统表示自己的系统出现了操作无响应的现象,如此大范围的影响,推测大概率是网关的功能出现了问题。

事故定位

立马上日志平台搜索Nginx处的请求日志,果然在Nginx上发现了大量的499响应码日志,紧接着拿着top 1请求量的499接口来搜索安全网关的日志,发现了大量的:java.lang.OutOfMemoryError: GC overhead limit exceeded,由于怕过年期间生产不稳定,从年前开始,已经很长时间都没有发布了,所以排除了新增的代码BUG。

解决

那么就有可能是长时间运行慢慢堆积的对象导致的OOM,直接重启安全网关,重启后成功解决。

覆盘

java.lang.OutOfMemoryError: GC overhead limit exceeded根据官方的解释是在多次gc后效果极差抛出的OOM。
怀疑可能存在内存泄漏,直接分析OOM后的dump文件。
在这里插入图片描述
从Dominator Tree图中排出占用内存最大的top n对象,挨个查看它的GC root:
在这里插入图片描述
再切换到Histogram,同样排出占用内存最大的top n对象,挨个查看GC root。

调优

分析后发现skywalking和spring产生了大量的Class对象,skywalking产生了大量的Endpoint对象,spring产生了大量的动态代理对象。并没有自身代码产生的内存泄漏对象。

  1. 适当的调大JVM堆大小
  2. 进一步调查Endpoint对象,是否可以控制过期时间。

事故的调查期间还发现了服务自启动以来只有过2次full gc,都是在启动初期由于Metaspace空间不足扩容导致的full gc,所以还需要调整Metaspace空间。

-XX:MetaspaceSize=128M

另外,我还调低了MaxTenuringThreshold,这个参数影响进入老年代的年龄阈值。
因为网关的对象都是请求级别的生命周期,分析gc日志可以知道young gc平均在30s执行一次,MaxTenuringThreshold的默认值是15,会导致部分长期存活对象需要将近8分钟的时间才能进入老年代,本来年轻代的空间就不大,再被这些长期存活对象一占用,会使得young gc更加频繁。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章