问题描述:

新接手了同事的一个项目,最近客户反映部署的系统频繁崩溃,导致不可用,简单查找原因是一个接口短时间频繁调用导致的。

Java如何识别生产环境 java生产环境问题_java

解决思路:

  1. 首先查找生产环境的日志,没有任何报错日志
  2. 查阅一些资料得知,可能是java堆内存溢出导致的问题,然后后面就开始操作了
  3. idea启动项目时,添加-XX:+HeapDumpOnOutOfMemoryError参数启动
  4. 模拟生产环境,开启十个线程同时访问接口,发现果然崩溃了,在项目根目录生成了内存快照java_pid5396.hprof
  5. 使用JProfiler工具打开,发现8个 实例竟然占据了97%的大小,仔细观察这个对象HeapByteBuffer,好像是关于网络请求缓存一类的
  6. 具体分析,又找到一个HeaderBuffer类,发现占据了104M,一个请求竟然占据104M,稍微几个请求就800多M了,这个就是接口崩溃的原因。
  7. 那一个请求怎么会占据这么大空间呢?在系统中搜索104这个关键字,果然找到了,竟然配置了每个网络请求的最大分配堆内存缓存(max-http-header-size)为104M,这样,如果一瞬间过来很多请求,第一个请求还没有释放,后面的请求就要求给自己也分配104M,物理机的空间又不是无限的,肯定会溢出
  8. 去掉这个属性后,再次运行,没问题了,查看了每次请求的分配堆缓存,只有6kb,圆满解决。

max-http-header-size知识点:

  1. 设置此参数大小为10M,则对于每个请求都会在堆上分配10M的缓存
  2. 设置此参数一般是为了解决前端请求Request header is too large的问题
    2.1 请求头超过了tomcat的限值。本来post请求是没有参数大小限制,但是服务器有自己的默认大小,所以需要设置服务器的请求大小

参考

Request header is too large问题解决记一次OOM问题排查过程