问题描述:
新接手了同事的一个项目,最近客户反映部署的系统频繁崩溃,导致不可用,简单查找原因是一个接口短时间频繁调用导致的。
解决思路:
- 首先查找生产环境的日志,没有任何报错日志
- 查阅一些资料得知,可能是java堆内存溢出导致的问题,然后后面就开始操作了
- idea启动项目时,添加-XX:+HeapDumpOnOutOfMemoryError参数启动
- 模拟生产环境,开启十个线程同时访问接口,发现果然崩溃了,在项目根目录生成了内存快照java_pid5396.hprof
- 使用JProfiler工具打开,发现8个 实例竟然占据了97%的大小,仔细观察这个对象HeapByteBuffer,好像是关于网络请求缓存一类的
- 具体分析,又找到一个HeaderBuffer类,发现占据了104M,一个请求竟然占据104M,稍微几个请求就800多M了,这个就是接口崩溃的原因。
- 那一个请求怎么会占据这么大空间呢?在系统中搜索104这个关键字,果然找到了,竟然配置了每个网络请求的最大分配堆内存缓存(max-http-header-size)为104M,这样,如果一瞬间过来很多请求,第一个请求还没有释放,后面的请求就要求给自己也分配104M,物理机的空间又不是无限的,肯定会溢出
- 去掉这个属性后,再次运行,没问题了,查看了每次请求的分配堆缓存,只有6kb,圆满解决。
max-http-header-size知识点:
- 设置此参数大小为10M,则对于每个请求都会在堆上分配10M的缓存
- 设置此参数一般是为了解决前端请求Request header is too large的问题
2.1 请求头超过了tomcat的限值。本来post请求是没有参数大小限制,但是服务器有自己的默认大小,所以需要设置服务器的请求大小
参考
Request header is too large问题解决记一次OOM问题排查过程