记一次中间件宕机以后持续请求导致应用OOM的排查思路(server.max-http-header-size属性配置不当的严重后果)
创始人
2024-12-10 20:06:36
0

一、背景

最近有一次在系统并发比较高的时候,数据库突然发生了故障,导致大量请求失败,在数据库宕机不久,通过应用日志可以看到系统发生了OOM

二、排查

初次看到这个现象的时候,我还是有点懵逼的,数据库宕机以后为什么会导致应用发生OOM呢?

不管怎么样,先按照传统思路,分析一下应用此时的dump文件。

通过MemoryAnalyzer工具进行dump文件分析,通过Leak Suspects页面可以发现,有两个可以点,如下:

在这里插入图片描述

system class loader看起来没有什么问题,org.apache.coyote.http11.Http11OutputBuffer对象占用这么多内存倒是真的可疑。

打开MemoryAnalyzer工具Dominator Tree页面,过滤org.apache.coyote.http11.Http11OutputBuffer,截图如下:

在这里插入图片描述

可以看到,内存中有大量org.apache.coyote.http11.Http11OutputBuffer对象,同时每个对象都持有一个2048000长度的字节数据。

通过在IDEA中对org.apache.coyote.http11.Http11OutputBuffer对象的引用发现,Http11OutputBuffer是用于tomcat处理请求时,用于每个请求处理时都会生成,代码如下:

org.apache.coyote.http11.Http11Processor#Http11Processor 

在这里插入图片描述

进入protocol.getMaxHttpRequestHeaderSize()方法:

在这里插入图片描述

进入getMaxHttpHeaderSize()方法:

在这里插入图片描述

可以看到maxHttpHeaderSize属性值默认是8192字节,怎么变成了上面的2048000长度了呢?

通过debug代码可以发现,在org.springframework.boot.autoconfigure.web.embedded.TomcatWebServerFactoryCustomizer#customizeMaxHttpHeaderSize方法中会进行覆盖设置,如果你在配置文件中配置了server.max-http-header-size属性,那么maxHttpHeaderSize默认的8192就会被覆盖。

同时,根据org.apache.coyote.http11.Http11Processor#Http11Processor源码,发现每次请求时也都会创建org.apache.coyote.http11.Http11InputBuffer对象,于是我又在MemoryAnalyzer工具Dominator Tree页面搜索了Http11InputBuffer类,如下:

在这里插入图片描述

此时,我发现为什么Http11InputBuffer对象持有的buffer大小不是2048000而是2056192,整整大了8192呢?

通过debug可以发现,答案可以在org.apache.coyote.http11.Http11InputBuffer#init方法中找到:

在这里插入图片描述

Http11InputBuffer对象中,buffer大小除了设置的size之外,还会加一个wrapper.getSocketBufferHandler().getReadBuffer().capacity(),通过代码调试可以发现,SocketBufferHandler的设置在org.apache.tomcat.util.net.NioEndpoint#setSocketOptions方法中进行的:

在这里插入图片描述

进入org.apache.tomcat.util.net.SocketProperties可以发现,buff的默认大小就是8192:

在这里插入图片描述

此时,问题排查基本结束了,排查中遇到的疑问也基本解决了。

三、原因

通过上面的分析可以发现,由于有人在配置文件中设置了server.max-http-header-size属性,

server:   max-http-header-size: 2048000 

覆盖了默认的8KB大小,导致每次请求创建的Http11InputBufferHttp11OutputBuffer对象持有的buffer大小增加到2MB,在数据库宕机以后,tomcat还在继续接受请求,由于请求响应阻塞,同时此时会有大量请求进行堆积,但是每次请求都会创建Http11InputBufferHttp11OutputBuffer对象,同时会向JVM申请内存,导致JVM内存使用量急剧增加,从而导致OOM

四、问题解决

找到问题原因以后,有点好奇,为什么要修改server.max-http-header-size属性呢?通过内部排查得知,原来是应用提供的某个接口是GET请求方式,在请求URL中拼接的参数过大的时候会报Request header is too large异常信息。

看到这个异常信息有点奇怪,为什么GET请求会有这个错误呢,为什么修改server.max-http-header-size属性可以解决呢?通过代码debug发现,Http11InputBuffer对象其实处理的是整个请求报文,包括请求头请求行等信息,所以GET方式请求URL大小和请求头大小都会被Http11InputBuffer对象持有的buffer大小限制,因此修改server.max-http-header-size属性确实可以解决GET请求方式由于URL过长导致的Request header is too large异常问题。

最后,将该GET请求方式接口修改成了POST方式请求,参数传递也通过请求体进行,删除配置文件中

server.max-http-header-size属性配置,恢复默认值8192,在测试环境进行测试,发现OOM问题可以解决。不过,虽然程序层面问题解决了,不过数据库稳定性问管理还需要进一步加强。

相关内容

热门资讯

六分钟教程!浙江游戏大厅双扣辅... 六分钟教程!浙江游戏大厅双扣辅助工具,财神十三张小程序辅助摆牌(原来真的有挂);1、下载好浙江游戏大...
实测揭晓!爱来掌中宝510k有... 实测揭晓!爱来掌中宝510k有挂吗,大咖互娱辅助,雀神小程序开通会员提高胜率(详细教程)一、爱来掌中...
5分钟辅助挂!三三麻将助赢神器... 5分钟辅助挂!三三麻将助赢神器,决战血流麻将跑得快都是真的有挂,微扑克教程(有挂技巧)1、进入到三三...
查到实测!wpk德州扑克靠靠谱... 查到实测!wpk德州扑克靠靠谱,新疆巴郎麻将助手,2025新版技巧(有挂技巧)1、新疆巴郎麻将助手系...
最新技巧!大唐麻将输赢设置,牵... 最新技巧!大唐麻将输赢设置,牵手跑得快辅助器ios,微信雀神小程序能开挂吗(详细教程);1、每一步都...
总算了解!!德扑ai智能机器人... 总算了解!!德扑ai智能机器人,博乐温州棋牌有没有挂,必备教程(有挂技巧)博乐温州棋牌有没有挂辅助器...
八分钟辅助挂!亲友起牌外 挂,... 八分钟辅助挂!亲友起牌外 挂,山东麻将果然真的有挂,存在挂教程(有挂方法);暗藏猫腻,小编详细说明亲...
6分钟技巧!心悦麻将吹牛输赢规... 6分钟技巧!心悦麻将吹牛输赢规律,大唐麻将推倒胡怎么设置(原来一直都是有挂);大唐麻将推倒胡怎么设置...
程序员教你!朋朋棋牌外挂怎么开... 程序员教你!朋朋棋牌外挂怎么开,棋乐棋牌有挂吗,雀神麻将小程序提高胜率(详细教程)在进入朋朋棋牌外挂...
今日重大通报!微扑克wpk安全... 今日重大通报!微扑克wpk安全,财神十三张的胜率机制是什么,必赢方法(有挂解说)1、财神十三张的胜率...