线上HTTP请求导致OOM【max-http-header-size配置不当引起】

文章目录

    • 起源
    • 项目环境
    • 分析问题
      • 1. 检查日志信息
      • 2. 进行模拟测试
      • 3. 查看Tomcat源码
      • 4. 检查系统
    • 解决方案
    • 名词解释
    • 小结

起源

新上线的一个项目,运行了半个月,突然出现频繁宕机(有大量的第三方接口请求业务),严重影响了业务系统的使用。

项目环境

Linux (3.10.0-957.el7.x86_64)
open JDK 1.8.32
SpringBoot 2.2.6.RELEASE
内嵌 Tomcat 9.0.47
配置最大堆内存配置 16G

分析问题

1. 检查日志信息

通过对日志检查,发现有下面的报错信息,从错误日志看,是由于出现了OOM错误,堆内存溢出导致的问题。

Exception in thread "http-nio-8080-exec-1011" java.lang.OutOfMemoryError: Java heap space
Exception in thread "http-nio-8080-exec-1031" java.lang.OutOfMemoryError: Java heap space
Exception in thread "http-nio-8080-exec-1052" java.lang.OutOfMemoryError: Java heap space

由于不知道程序是哪一部分的代码或者配置出现的问题,所以计划模拟OOM场景,并导出dump文件进一步分析。

2. 进行模拟测试

  1. 在idea中配置出现OOM的jvm参数,如下所示:
-Xms1024M -Xmx1024M -XX:+HeapDumpOnOutOfMemoryError

线上HTTP请求导致OOM【max-http-header-size配置不当引起】_第1张图片

  1. 通过JMeter工具,模拟生产环境,开启十个线程发送1000笔请求同时访问接口,发现复现了以上的OOM,并在项目根目录生成了内存快照java_pid4521.hprof。

  2. 使用VisualVM工具打开,发现20个实例竟然占据了98%的大小,其中byte数组中占用了大量的资源,展开细看发现有很多Http11InputBuffer和Http11OutputBuffer实例,经查阅资料得知,均是关于网络请求缓存一类的。
    Http11InputBuffer线上HTTP请求导致OOM【max-http-header-size配置不当引起】_第2张图片Http11OutputBuffer
    线上HTTP请求导致OOM【max-http-header-size配置不当引起】_第3张图片

3. 查看Tomcat源码

org.apache.coyote.http11.Http11Processor#Http11Processor

    public Http11Processor(AbstractHttp11Protocol<?> protocol, Adapter adapter) {
        super(adapter);
        this.protocol = protocol;

        httpParser = new HttpParser(protocol.getRelaxedPathChars(),
                protocol.getRelaxedQueryChars());

        inputBuffer = new Http11InputBuffer(request, protocol.getMaxHttpHeaderSize(),
                protocol.getRejectIllegalHeaderName(), httpParser);
        request.setInputBuffer(inputBuffer);

        outputBuffer = new Http11OutputBuffer(response, protocol.getMaxHttpHeaderSize());
        response.setOutputBuffer(outputBuffer);

org.apache.coyote.http11.AbstractHttp11Protocol

    /**
     * Maximum size of the HTTP message header.
     */
    private int maxHttpHeaderSize = 8 * 1024;
    public int getMaxHttpHeaderSize() { return maxHttpHeaderSize; }

经查看源码得知,tomcat对于inputBuffer和outputBuffer的HTTP请求header大小,初始化默认都是8 * 1024。

4. 检查系统

在代码里进行了全局检索,终于发现了类似于header的配置:server.max-http-header-size,设置的为102M。一次inputBuffer就会有一次outputBuffer,即每次请求相当于占用了双倍,没及时释放就会积累,况且JVM分配的内存和本身物理机器空间也不是无限的,当请求数量过多,必然会出现内存溢出的问题,到此,基本已经确定了,就是这个不合理的最大http请求头参数导致的问题。

解决方案

我们把如下配置文件中的参数去掉,保留默认的配置,进行压力测试后,发现没有出现过OOM现象,自此该问题得以解决。

> server.max-http-header-size=102400000

名词解释

  • OOM:指应用系统中存在无法回收的内存或使用的内存过多,导致的内存溢出。
  • 堆内存:是JVM中用于存放对象的一块内存区域,Java程序中所有new出来的对象都会被存放在堆内存中。
  • JMeter:自动化测试工具,官网链接:https://jmeter.apache.org/download_jmeter.cgi。
  • VisualVM:性能分析工具,官网链接:https://visualvm.github.io/。

小结

  • max-http-header-size参数默认8Kb。
  • 在应用系统中配置参数时,建议理解参数的含义,不能盲目的添加。
  • 上线的系统各个接口及功能,必须要有压力测试。
    线上HTTP请求导致OOM【max-http-header-size配置不当引起】_第4张图片

你可能感兴趣的:(07-JAVA,http,java,spring,boot,jvm)