ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

maxHttpHeaderSize设置过大导致的内存溢出

2021-04-15 20:03:45  阅读:2351  来源: 互联网

标签:java Http11OutputBuffer .. 内存 coyote apache org maxHttpHeaderSize 溢出


一、生产案发现场以及排查过程

3月23日晚上22:46:06,front服务挂掉发生告警,查看系统日志:

可以看到堆栈溢出。

 

马上猜想到跟下午新增的一个配置有关:

server.maxHttpHeaderSize: 10240000

(赶紧回滚镜像,恢复生产。。。)

 

猜想归猜想,还是得拿出点证据。

服务对应的jvm参数:

java -Xms1024m -Xmx1024m -XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=512m -XX:SoftRefLRUPolicyMSPerMB=5000 -XX:+PrintGCDetails -Xloggc:/data/logs/saas-front/log/gc/gc.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/logs/saas-front/log/oom -javaagent:/usr/local/skywalking/skywalking-agent/skywalking-agent.jar -Dskywalking.agent.service_name=saas-front-aws_us_west_2 -jar saas-front.jar --spring.profiles.active=aws_us_west_2

于是可以去/data/logs/saas-front/log/oom目录拿到OOM后的快照,使用Eclipse Memory Analyzer工具进行分析。

 

 

很快啊,查看Leak Suspects就可以发现两个溢出点:

 

Problem Suspect 1:

42 instances of "org.apache.coyote.http11.Http11OutputBuffer", 
loaded by "sun.misc.Launcher$AppClassLoader @ 0xc0015438" 
occupy 430,106,544 (44.09%) bytes.
Biggest instances:
org.apache.coyote.http11.Http11OutputBuffer @ 0xc5860360 - 10,240,632 (1.05%) bytes.
org.apache.coyote.http11.Http11OutputBuffer @ 0xc586b6b0 - 10,240,632 (1.05%) bytes.
org.apache.coyote.http11.Http11OutputBuffer @ 0xc7b733a0 - 10,240,632 (1.05%) bytes.
org.apache.coyote.http11.Http11OutputBuffer @ 0xca055528 - 10,240,632 (1.05%) bytes.
org.apache.coyote.http11.Http11OutputBuffer @ 0xccc2d290 - 10,240,632 (1.05%) bytes.
org.apache.coyote.http11.Http11OutputBuffer @ 0xcd5f51f0 - 10,240,632 (1.05%) bytes.
......

存在42个Http11OutputBuffer实例,每个占用了10M,一共占用了420M(44.09%)的堆空间。

可以看出是tomcat的线程占用的空间。

 

Problem Suspect 2:

945 instances of "byte[]", loaded by "<system class loader>" 
occupy 420,340,888 (43.09%) bytes.
Biggest instances:
byte[10248192] @ 0xc4bc2c10 GET / HTTP/1.1..host:honedora.comm..x-real-ip:43.245.160.455..x-forwarded-for:43.245.160.455..user-agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.366..accept-language:en-US,en;q=0.55..... - 10,248,208 (1.05%) bytes.
byte[10248192] @ 0xc70776d8 GET / HTTP/1.1..host:thenicegoods.comm..x-real-ip:43.245.160.455..x-forwarded-for:43.245.160.455..user-agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.366..accept-language:en-US,en;q=0.... - 10,248,208 (1.05%) bytes.
byte[10248192] @ 0xc7b7bc00 GET /prometheus HTTP/1.1..host:172.30.2.144:180222..user-agent:Prometheus/2.17.11..accept:application/openmetrics-text; version=0.0.1,text/plain;version=0.0.4;q=0.5,*/*;q=0.11..accept-encoding:gzipp..x-prometheus-scrape-timeout-seconds:10.0000000............. - 10,248,208 (1.05%) bytes.
byte[10248192] @ 0xc943e7e8 GET //website/wp-includes/wlwmanifest.xml HTTP/1.1..host:cattyy.comm..x-real-ip:43.245.160.455..x-forwarded-for:43.245.160.455..cookie:client_id=5718685622856744966..user-agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko... - 10,248,208 (1.05%) bytes.
......

存在945个byte[]实例,其中40多个最大的实例一共占用了400M空间。

这里还是tomcat线程占用的空间。

 

基本上这里可以确定tomcat配置的最大请求头信息大小有问题。

 

 

二、当初为什么设置这个参数-maxHttpHeaderSize

前面发现访问某个商品链接页面报500:

 

查看服务的报错日志:

10:29:08.901 user [http-nio-8022-exec-9] ERROR o.a.coyote.http11.Http11Processor - Error processing request
org.apache.coyote.http11.HeadersTooLargeException: An attempt was made to write more data to the response headers than there was room available in the buffer. Increase maxHttpHeaderSize on the connector or write less data into the response headers.
	at org.apache.coyote.http11.Http11OutputBuffer.checkLengthBeforeWrite(Http11OutputBuffer.java:464)
	at org.apache.coyote.http11.Http11OutputBuffer.write(Http11OutputBuffer.java:417)
	at org.apache.coyote.http11.Http11OutputBuffer.write(Http11OutputBuffer.java:403)
	at org.apache.coyote.http11.Http11OutputBuffer.sendHeader(Http11OutputBuffer.java:363)
	at org.apache.coyote.http11.Http11Processor.prepareResponse(Http11Processor.java:975)
	at org.apache.coyote.AbstractProcessor.action(AbstractProcessor.java:369)
	at org.apache.coyote.Response.action(Response.java:211)
	at org.apache.coyote.Response.sendHeaders(Response.java:437)
	at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:281)
	at org.apache.catalina.connector.OutputBuffer.close(OutputBuffer.java:241)
	at org.apache.catalina.connector.Response.finishResponse(Response.java:440)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:374)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:853)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1587)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:748)

报错提示请求头缓存区空间不够用,说是可以加大maxHttpHeaderSize这个值或者减少写入数据。

我当时的解决方法:

1、根据网上所说,springboot可以直接配置server.maxHttpHeaderSize = 10M

 

2、后面排查到了写入响应头过大的URL,通过修改代码逻辑来减少不必要的写入

有一个接口www.baidu.com/products/shoe,接口执行流程是

①查询商品

②拦截器拦截设置店铺通用model

③根据某些逻辑判断链接是否需要重定向

- true 重定向

- false 返回跳转到商品详情页

 

重定向的结果是,model会在链接后面拼接了大量参数

www.baidu.com/products/new-shoe?cardConfig=***&name=***&customCodeList=***&deviceType=***省略...

并且会往响应头里面设置Location = 上面这条重定向的url,用于告诉浏览器重定向跳转。(这里是报错原因)

而返回到商品详情页,model是会用于页面显示或者页面js逻辑判断。

于是我在拦截器里面做了判断,如果属于重定向,那么不设置model。

 

然后①②都修改完上线,没过多久,就出现了前面的OOM。。。

 

三、来谈谈maxHttpHeaderSize

maxHttpHeaderSize参数是属于tomcat服务器的参数,默认是8k,springboot内置tomcat默认配置8k。

在tomcat的server.xml 里面也可以设置maxHttpHeaderSize。

<Connector port="8099" protocol="HTTP/1.1" maxHttpHeaderSize="8192" connectionTimeout="20000" redirectPort="8443" />

 

Tomcat对servlet规范中的response和request做了实现,其中会有一个Buffer用于缓存httpHeader信息。

如下图,coyoteResponse的Header Buffer会控制着httpheader的存储。

这个Header Buffer是不可以扩充的,tomcat启动的时候会设置它的固定大小(默认8192字节),无论是请求头的输出还是输入都不可以超出这个大小。

 

而这个固定大小正是maxHttpHeaderSize来配置的。

 

 

我们可以通过一个例子验证一下,

springboot配置

server.max-http-header-size: 666666666

写一个测试接口,Debug查看:

可以看到,coyoteResponse底下确实有一个headerBuffer对象,里面有一个hb的属性,是byte数组,大小为666666666

 

四、总结

前面堆栈信息显示的对象org.apache.coyote.http11.Http11OutputBuffer @ 0xc5860360,也是对应

这里的Header Buffer,每一个tomcat用户线程都会申请一块Header Buffer空间。

 

当网站并发线程比较多的时候,内存空间占用比较大,从而导致新的线程没办法申请内存空间,最终出现OOM。

 

maxHttpHeaderSize这个参数不能设置过大,根据项目情况设置足够用即可,还要充分考虑设置请求头的大小和数量,是否有优化的空间。

 

标签:java,Http11OutputBuffer,..,内存,coyote,apache,org,maxHttpHeaderSize,溢出
来源: https://blog.csdn.net/deel_feel/article/details/115736614

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有