记一次OOM问题排查过程
上周运维反馈线上程序出现了OOM,程序日志中的输出为
Exception in thread "http-nio-8080-exec-1027" java.lang.OutOfMemoryError: Java heap space
Exception in thread "http-nio-8080-exec-1031" java.lang.OutOfMemoryError: Java heap space
复制代码
看线程名称应该是tomcat的nio工作线程,线程在处理程序的时候因为无法在堆中分配更多内存出现了OOM,幸好JVM启动参数配置了-XX:+HeapDumpOnOutOfMemoryError,使用MAT打开拿到的hprof文件进行分析。
第一步就是打开Histogram看看占用内存最大的是什么对象:
可以看到byte数组占用了接近JVM配置的最大堆的大小也就是8GB,显然这是OOM的原因。 第二步看一下究竟是哪些byte数组,数组是啥内容: 可以看到很明显这和HTTP请求相关,一个数组大概是10M的大小。 第三步通过查看GC根查看谁持有了数组的引用: 这符合之前的猜测,是tomcat的线程在处理过程中分配了10M的buffer在堆上。至此,马上可以想到一定是什么参数设置的不合理导致了这种情况,一般而言tomcat不可能为每一个请求分配如此大的buffer。 第四步就是检查代码里是否有tomcat或服务器相关配置,看到有这么一个配置:
max-http-header-size: 10000000
复制代码
至此,基本已经确定了八九不离十就是这个不合理的最大http请求头参数导致的问题。 到这里还有3个疑问:
- 即使一个请求分配10M内存,堆有8GB,难道当时有这么多并发吗?800个tomcat线程?
- 参数只是设置了最大请求头10M,为什么tomcat就会一次性分配这么大的buffer呢?
- 为什么会有如此多的tomcat线程?感觉程序没这么多并发。
先来看问题1,这个可以通过MAT在dump中继续寻找答案。 可以打开线程视图,搜索一下tomcat的工作线程,发现线程数量的确很多有401个,但是也只是800的一半:
再回到那些大数组的清单,按照堆分配大小排序,往下看: 可以发现除了有10008192字节的数组还有10000000字节的数组,查看引用路径可以看到这个正好是10M的数组是output buffer,区别于之前看到的input buffer: 好吧,这就对了,一个线程分配了输入输出两个buffer,占用20M内存,一共401个线程,占用8GB,所以OOM了。 还引申出一个问题为啥有这么多工作线程,
再来看看问题2,这就需要来找一下源码了,首先max-http-header-size是springboot定义的参数,查看springboot代码可以看到这个参数对于tomcat设置的是MaxHttpHeaderSize:
然后来看看tomcat源码: 进一步看一下input buffer:buffer大小是MaxHttpHeaderSize+ReadBuffer大小,后者默认是8192字节:
<attribute name="socket.appReadBufSize" required="false"><p>(int)Each connection that is opened up in Tomcat get associated witha read ByteBuffer. This attribute controls the size of this buffer. Bydefault this read buffer is sized at <code>8192</code> bytes. For lowerconcurrency, you can increase this to buffer more data. For an extremeamount of keep alive connections, decrease this number or increase yourheap size.</p></attribute>
复制代码
这也就是为什么之前看到大量的buffer是10008192字节的。显然还有一批内容是空的10000000字节的buffer应该是output buffer,来看看源码:
嗯这是一个header buffer,所以正好是10000000字节。
至于问题3,显然我们的应用程序是配置过最大线程的(查看配置后发现的确,我们配置为了2000,好吧有点大),否则也不会有401个工作线程(默认150),如果当时并发并不大的话就一种可能,请求很慢,虽然并发不大,但是因为请求执行的慢就需要更多线程,比如TPS是100,但是平均RT是4s的话,就是400线程了。这个问题的答案还是可以通过MAT去找,随便看几个线程可以发现很多线程都在等待一个外部服务的返回,这说明外部服务比较慢,去搜索当时的程序日志可以发现有很多"feign.RetryableException: Read timed out executing的日志"。。。。追杀下游去!慢点,我们的feign的timeout也需要再去设置一下,别被外部服务拖死了。
记一次OOM问题排查过程相关推荐
- golang 记一次data race排查过程
golang 记一次data race排查过程 背景 data race 现场 解决思路 经验总结 data race在写并发代码时候经常遇到,相关基础概念的介绍可以参考之前一篇文章:golang d ...
- 记一次网站故障排查过程(nginx 504状态码、 upstream timed out (110: Connection timed out)以及jbd2引起IO高
一.问题描述 客户侧反馈无法正常访问系统,页面转圈,时好时坏,访问不稳定. 二.系统环境: 机器环境:UOS . nginx .php(对接其他服务器kingbase .钉钉.redis .KF) E ...
- 一个比较明显的OOM的排查过程
淘江湖由于之前遇到过因爬虫导致对用户中心的访问飚高而险些发生问题的情况,所以在其最近的一个项目中升级TDDL到2.4.4版本,以使用tddl的流控功能.但是在一次压测6个小时后产生了OOM异常.用晓锋 ...
- 记一次Kafka warning排查过程
1.前因 在配合测试某个需求的时候,正好看到控制台打印了个报错,如下: 2023-03-06 17:05:58,565[325651ms][pool-28-thread-1][org.apache.k ...
- 记一次SOFA内存泄漏排查过程
记一次内存泄漏排查过程 起因 某天中午大家还在安静的午休,睡得正香的时候突然被一阵手机滴-滴滴直响短信惊醒.一看是应用的服务器告警并且对应服务的所有机器都在告警"健康检查失败,自动拉下线&q ...
- 转:记一次linux oom内存溢出排查过程
@转:记一次linux oom内存溢出排查过程 记一次linux oom内存溢出排查过程 2018年08月16日 14:13:49 enchanterblue 阅读数 4099更多 分类专栏: --- ...
- 多队列 部分队列没有包_记一次TCP全队列溢出问题排查过程
简介:记一次TCP全队列溢出问题排查过程 1. 前言 本文排查的问题是经典的TCP队列溢出问题,因TCP队列问题在操作系统层面没有明显的指标异常,容易被忽略,故把排查过程分享给大家. 2. 问题描述 ...
- 一次堆外OOM问题的排查过程
转载自 一次堆外OOM问题的排查过程 背景 线上服务有一台机器访问不通(一个管理平台),在公司的服务治理平台上查看服务的状况是正常的,说明进程还在.进程并没有完全crash掉.去线上查看机器日志, ...
- 记一次线上服务假死排查过程
大家好,我是烤鸭: 最近线上问题有点多啊,分享一个服务假死的排查过程. 问题描述 9点10分,收到进程无响应报警(一共6台机器,有1台出现),后来又有1台出现. 排查思路 首先确认是否误报或者网络抖动 ...
最新文章
- java如何调windows框_java – JDialog.setAlwaysOnTop(true)将所有对话框带到Windows下的前面...
- memcpy和strcpy的区别及memcmp和strcmp的区别
- 日志ILog(文件日志/控制台日志/控件日志/网络日志)
- 前端学习(1378):express静态资源处理
- 太阳系行星运转示意图
- MT4外汇结余净值可用预付款
- 晚上如何配置ubuntu,保护眼睛?黑(暗)色主题
- Top-Down Bottom-Up
- Eclipse设置字体和大小
- nyoj451 光棍节的快乐
- OpenWorm项目
- 罗斯蒙特流量计调试需要考虑的两大方面
- NSIS教程(8): 基于第三方界面库的安装包界面
- 实现云桌面解决方案需要用到哪些东西
- “神奇“的表插入排序算法
- Cesium 三维模型使用 blender 调整位置、坐标轴、比例等
- android add fragment,fragment中的add和replace方法的区别浅析
- 知识管理,浏览器收藏夹,经常访问的网站
- 直播运营应该具备哪些技能
- 免费又好用的程序员笔记应用Boostnote for mac