记一次故障排查
记录一次生产问题排查
现象
生产一个导入导出服务频繁掉线,看监控指标发现GC频繁,应用内存快要达到上限。怀疑有业务代码有大内存问题,或者客户大数据操作。
紧急处理方式
调大一倍JVM内存,看下是否能跑过此业务。
分析
从
top -H
看到进程内部线程PID
为28665
的线程占用CPU高PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 28665 tomcat 20 0 8680236 4.753g 17396 R 99.9 30.3
转换成16进制是
6ff9
$ printf %x 28665 6ff9%
从
jstack
查找nid=0x6ff9
线程是神秘"TaskExecutor-Run-23" #539 prio=5 os_prio=0 tid=0x00007f2ce409d800 nid=0x6ff9 runnable [0x00007f2c68ea3000] java.lang.Thread.State: RUNNABLE at java.util.ArrayList.indexOf(ArrayList.java:316) at org.apache.poi.xssf.model.StylesTable.putStyle(StylesTable.java:247) at org.apache.poi.xssf.usermodel.XSSFCell.setCellStyle(XSSFCell.java:502) /// 忽略业务代码
从连续的
jstack & top -H
中发现,都是此业务代码占用cpu,从内存dump里面发现,大内存占用也是此业务方法的线程查看业务代码发现业务代码的POI写法有问题
SXSSFWorkbook book = new SXSSFWorkbook(new XSSFWorkbook(inputStream), 500); Sheet sheet0 = book.getXSSFWorkbook().getSheetAt(0); // 省略对sheet0的操作 // book.getSheetAt(0) 改成这样,业务上用SXSSFWorkbook能够满足。
这样实际上拿到的是
XSSFWorkbook
,并没有使用流式的SXSSFWorkbook
,这样所有的数据都会加载到内存里面,导致内存飙升。 内存飙升导致GC频繁,GC暂停时间过长,触发断路器断路,从而触发断路告警。