一、问题描述
项目现场压测登陆接口,说并发30左右服务就会卡死。由于现场不能通过外网远程连接,只能本地复现下(配置文件、项目版本、启动参数等都保持一致)。
压测工具:jemeter
压测功能:登陆接口
问题简述:并发30,后端出现OOM。
二、解决思路
没想到居然真的复现了,既然是排查OOM,就用java自带的VisualVM工具吧,需要初步排查是哪些对象占用了堆内存。
1、使用VisualVM排查jvm内存:
(1)目录在C:\Program Files\Java\jdk1.8.0_144\bin下,有个jvisualvm.exe。
(2)启动后,选择本地连接,连上自己的测试项目。
示例图一个是jemeter,一个是测试项目
连上后的效果,可以看到cpu、堆内存、元空间、类加载数量、线程等信息(jemeter为例):
(4)使用jemeter压测30个线程并发(测试项目为例):
可以看到,压测开始的那一瞬间,cpu直接飙升,而且堆空间的使用空间也飙升。点击右上角,看堆信息:
点击 类 -> 大小排序,发现byte[]数组实例只有0.5%,但是却占用了91%的内存空间!!!那说明每个byte[]对象都是大对象!查看下大对象:
找重复的对象,然后看下,发现一点端倪
①后端报错的是http-nio连接;
②堆信息显示的大对象也是http相关的:
③后端效果,接口并没有打印相关执行日志且有full gc发生;
可以大胆猜测是tomcat的问题
2、检查配置文件
配置文件:
看到配置文件发现4、6行居然和大对象的size一样?!测试后发现,max-http-header-size才是罪魁祸首,将该参数调小至实际情况即可。
三、解决方案
配置文件max-http-header-size属性,根据项目实际情况配置。
四、小结
1、max-http-header-size是请求头参数大小,tomcat会创建预留空间,即使header实际参数没那么大,也会创建那么大的空间。
2、从二.1.(4)最后的大对象属性图能看出来,tomcat会按照max-http-header-size的配置属性创建两个对象,这也解释了为什么2G内存的JVM在30并发左右就OOM+FULL GC了(2048 / 60 =34.13 )
3、max-http-header-size默认配置,tomcat 5是4kb,tomcat 8是8kb