栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

记一次 max-http-header-size 配置不当导致的 OOM 问题

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

记一次 max-http-header-size 配置不当导致的 OOM 问题

一.起因

工作时接手的一个项目线上 Full GC 次数过于频繁,最后 OOM 导致服务挂掉。

通过配置的 -XX:+HeapDumponOutOfMemoryError 拿到事故内存快照使用 MAT 进行分析。

二.项目环境

Linux (3.10.0-957.21.3.el7.x86_64)JDK 8SpringBoot 2.2.4.RELEASE内嵌 Tomcat 9.0.3配置最大堆内存配置 4G 三.MAT 分析 1.查看类实例 Histogram 直方图

首先可以看到 byte 数组占用了大量内存

Shallow Heap(浅堆)代表对象本身占用的内存,包含对象的对象头,实例数据、对齐空间。
Retained Heap(深堆)代表对象本身和对象关联的对象占用的内存,该对象被回收后,能够释放的内存大小。
2.查看 GC 根谁持有了数组的引用

exclude all phantom/weak/soft etc. reference 排除掉 软、弱、虚引用,只剩下强引用。因为除了强引用之外,其他引用都可以被 JVM GC 掉,如果一个对象始终无法被 GC,说明有强引用的存在,导致 GC 过程一直得不到回收,最终内存溢出、

我们排除掉软、弱、虚引用,因为这几种是不会造成内存泄漏的,可以先不用管它,我们只需要看排除后还有没引用存在,有的话 那就是强引用了


发现这和HTTP请求有关,都是Tomcat线程

通过排查可以定位到 Http11InputBuffer 和 Http11OutputBuffer 两个缓冲对象都持有大数组。差不多每一个请求线程就占用 20 M,这显然是不合理的,应该是哪配置不规范导致的。

于是检查项目 yml 配置发现一条设置 max-http-header-size 属性与分配的内存相似。

server:
  max-http-header-size: 1024000

该字段为设置 HTTP 消息头的最大大小。
其 Tomcat 默认设置的大小为 8 * 1024B 大小

四.疑问:为什么设置消息头最大的大小会实际分配对应大的内存

org.apache.coyote.http11.Http11Processor#Http11Processor

可以看到输入输出缓冲对象初始化时携带上了设置了 maxHttpHeaderSize,进一步查看

1.Http11InputBuffer 初始化

只是初始化了下 Http11InputBuffer#headerBufferSize 属性值。
具体使用的地方为 org.apache.coyote.http11.Http11InputBuffer#init 方法

在定义缓冲区长度时,maxHttpHeaderSize(1024000) 额外添加了套接字通信的缓冲区大小(8192),所以在 GC 根链路上看到的 byteBuffer 所持数组大小为 10248192

allocate 方法会返回指定大小的 HeapByteBuffer 大小的缓冲区

2.Http11OutputBuffer 初始化


outputBuffer 就在初始化的时候,就创建好了对应大小的缓冲区。此处就直接创建使用 maxHttpHeaderSize 大小。

对应上图 headerBuffer 所持数组 1024000 大小

五.流程分析

Tomcat 接收请求时

    NioEndpoint 将请求封装为 NioEndpoint$SocketProcessor 交给 Tomcat ThreadPoolExecutor 执行处理执行调用 AbstractProtocol$ConnectionHandler 的 process 方法内部使用 HTTP11NioProtocol 处理此请求,会实例化一个 Http11Processor ,最终调用其 process 方法处理在 Http11Processor 实例化时会直接初始化一个 [10240000] 大小的 Http11OutputBuffer,处理连接时再初始化 Http11InputBuffer 的大小平均每个线程持有 20M 大小的缓存数组,当并发请求时,线程池里的线程数达到200时,超出了设置的最大堆内存 4G 导致 OOM
六.处理

根据该项目实际查看,请求传递参数不多,删除配置设置的请求头大小,使用默认参数即可

后续使用 jmeter 进行压测监控,内存基于稳定,不出现 OOM 问题。

看 Git 提交记录为 init 时就有了,怀疑是 copy 其他项目来着就一直用着了,为后续留下坑。


以上为对该 OOM 问题的一次排查过程记录,还是有很多知识点没有扫到,仍待继续学习。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/712893.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号