页面请求频繁导致Http11OutputBuffer触发OOM解决

2022-11-28 18:47:26 浏览数 (1)

文章目录
  • 问题描述
  • 解决方案
    • Leak Suspects
    • Dominator Tree
    • Top Consumers

问题描述

新接手的项目,测试反馈页面同时点击速度快些请求就会报错,返回nginx 502。

Failed to complete processing of a request ,看报错的意思是处理请求失败导致的OOM。本人也在前台点击测试,确实有这个问题,关键是请求也不多,怎么会导致OOM呢?

解决方案

通过arthas查看服务器的CPU还是很稳定的,就是内存比较吃紧,fullGC比较频繁。 接下来我通过jmap命令导出对应进程的dump日志,命令如下:

代码语言:javascript复制
jmap -dump:format=b,file=datadump_pid3380.hprof 3380

下载对应的dump日志,通过MAT(Memory Analyzer Tool)工具查看分析对应的dump日志,结果如下:

重点关注下Histogram、Dominator Tree、Top Consumers、Duplicate Classes、Leak Suspects 名称解释:

  • Histogram:直方图:列出每个类的实例数量
  • Dominator Tree:支配树:列出最大的对象和它们保持存活的对象。
  • Top Consumers:内存高占比消费对象:打印消耗最多的对象,并按类和包分组。
  • Duplicate Classes:重复类:检测由多个类装载装载的类。
  • Leak Suspects:泄漏疑点:包括泄漏疑点和系统概述

Leak Suspects

可以看到两个泄露疑点,都占了400M,指向的都是普通的接口请求,这是为啥?接下来我们看下关联树。

Dominator Tree

通过shallow heap(浅堆)和retained heap(保留堆)的大小判断可以看到最大的其实是byte类型。我们展开org.apache.coyote.http11.Http11OutputBuffer对象,进一步查看空间占用情况。 PS:名词解释: shallow heap:对象本身的大小,如果是数组或集合则是各个元素的总大小。 retained heap:对象本身的大小 引用的其他对象的大小。

可以看到都存储在java.nio.HeapByteBuffer对象中。 名词解释:Heap BufferQ(堆缓冲区) 这是最常用的类型,ByteBuf将数据存储到JVMO的堆空间中,并且将实际的数据存放到byte array中来实现。

  • 优点:由于数据是存储在JVM的堆中,因此可以快速的创建与快速的释放,并且它提供了直接访问内部字节数组的方法。
  • 缺点:每次读写数据时,都需要先将数据复制到直接缓冲区中再进行网络传输。

通过相关类初步可以判定是请求相关的问题,请求返回的头信息并且不包含消息体,剩下的都是000也就是空内容。就是请求返回头的数据缓冲区过大导致.而且属于tomcat包下面,但项目用的是SpringBoot内置的Tomat,按理不会有这种问题,我们继续向下查看。

Top Consumers

查看最大占比的内存消费都指向了tomcat下面的包,最大的一些对象看到基本上都是100MB,还都与请求相关,所以接下来查看是不是哪里配置了这个,因为都是100MB还指向接口也太巧了。 查看配置文件找到了元凶:

max-http-header-size居然被配置成了100MB,默认值是8KB,所以我暂且把这块注释掉,让它使用默认值,Jenkins重新构建发布项目后,同时多人测试验证,没有再出现nginx 502问题,应用程序也没有再出现OOM异常。之前为啥会把max-http-header-size配置这么大目前我还不知道啥原因,猜测是有啥特殊需求要传大header?正常也不应该把大数据放在请求头里面,后续有需要再继续调整优化了。

本文内容到此结束了, 如有收获欢迎点赞

0 人点赞