目录
- 关于max-http-header-size配置
- 概述
- Max-HTTP-Header-Size
- 请求头太大
- max-http-header-size配置不合理导致OOM问题排查
- 1. 首先线上vm参数配置-XX:+HeapDumpOnOutOfMemoryError
- 2. 使用Jprofiler分析下占用最大的空间是 char[]数组
- 3. 看下OOM栈信息
- 4. 定位源码
- 5. 查看char[]里面具体内容
- 6. 综合上述情况,可以得出一下结论
- 7. 为什么会分配那么大的请求头?是否和某个配置相关吗?
关于max-http-header-size配置
概述
默认情况下,Spring Boot Web 应用程序包括一个预配置的嵌入式 Web 服务器。但是,在某些情况下,我们希望修改默认配置以满足自定义要求。
在本教程中,讲解如何在 Spring Boot 2.x 应用程序的application.properties文件中对请求标头进行设置和使用max-http-header-size属性。
Max-HTTP-Header-Size
Spring Boot 支持Tomcat、Undertow和Jetty作为嵌入式服务器。通常,我们在 Spring Boot 应用程序中的application.properties文件或application.yaml文件中进行服务器配置。
大多数 Web 服务器都有自己的一组 HTTP 请求header大小限制。HTTP header值受服务器实现的限制。在 Spring Boot 应用程序中,最大 HTTP header大小是使用server.max-http-header-size 配置的。Tomcat和Jetty的实际默认值为8kB,Undertow的默认值为1MB。
要修改最大 HTTP header大小,在application.properties文件中进行如下配置:
server.max-http-header-size=1024000
从 Spring Boot 2.1 开始,可使用DataSize可解析值:
server.max-http-header-size=10KB
请求头太大
假设发送的请求的总 HTTP header大小大于max-http-header-size值。服务器以“400 Bad request”错误拒绝请求。在下一个示例中,我们将在日志文件中看到此错误。
让我们创建一个控制器,它有一个名为 token 的header属性:
@RestController @RequestMapping(value = "/request-header-test") public class MaxHttpHeaderSizeController { @GetMapping public boolean testMaxHTTPHeaderSize(@RequestHeader(value = "token") String token) { return true; } }
接下来,让我们向application.properties文件添加一些属性:
## Server connections configuration server.tomcat.threads.max=200 server.connection-timeout=5s server.max-http-header-size=8KB server.tomcat.max-swallow-size=2MB server.tomcat.max-http-post-size=2MB
当我们在token中传递一个大小大于 8kb的字符串值时,得到 400 错误,如下所示:
max-http-header-size配置不合理导致OOM问题排查
#线上max-http-header-size导致oom问题排查
1. 首先线上vm参数配置-XX:+HeapDumpOnOutOfMemoryError
线上oom后会生成java_pidxxx.hprof文件
2. 使用Jprofiler分析下占用最大的空间是 char[]数组
3. 看下OOM栈信息
// 这里把栈信息粘贴出来看一下 Thread dump at 27588:02.814.491 * Thread group "main": Thread "http-nio-51026-exec-115": at java.lang.OutOfMemoryError.<init>() (line: 48) at java.nio.HeapByteBuffer.<init>(int, int) (line: 57) at java.nio.ByteBuffer.allocate(int) (line: 335) at org.apache.coyote.http11.Http11OutputBuffer.<init>(org.apache.coyote.Response, int) (line: 110) at org.apache.coyote.http11.Http11Processor.<init>(org.apache.coyote.http11.AbstractHttp11Protocol, org.apache.coyote.Adapter) (line: 163) at org.apache.coyote.http11.AbstractHttp11Protocol.createProcessor() (line: 1001) at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(org.apache.tomcat.util.net.SocketWrapperBase, org.apache.tomcat.util.net.SocketEvent) (line: 853) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun() (line: 1590) at org.apache.tomcat.util.net.SocketProcessorBase.run() (line: 49) at java.util.concurrent.ThreadPoolExecutor.runWorker(java.util.concurrent.ThreadPoolExecutor$Worker) (line: 1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run() (line: 624) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run() (line: 61) at java.lang.Thread.run() (line: 748)
4. 定位源码
可以看到多半就是分配headerBufferSize导致的了
5. 查看char[]里面具体内容
不难发现数组后面大部分元素都是0
6. 综合上述情况,可以得出一下结论
- OOM是因为分配请求头太大导致的
- 分配的char[]数组大部分空间都未使用到
7. 为什么会分配那么大的请求头?是否和某个配置相关吗?
排查配置发现
server: max-http-header-size: 10485760 #10M,值太大,并发量一上来服务就内存溢出了 # max-http-header-size单位为字节,默认值为8*1024字节=8kb
修改配置前和修改后再次压测,修改后发现不会有这种情况了。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持自由互联。