大数据量报表导出导致的生产页面卡死问题,OOM问题

前两天,客户反映我们的系统平台突然不能访问了,登录界面的验证码都加载不出来,然后运维人员也报告,我们有一台服务器的CPU使用率飙升至99%,且长时间下不来,这让我的脑瓜子咔咔疼。经过繁琐的手续在CPU自动降下来后,终于拿到生产日志,果不其然,内存溢出,可问题是,当时的情况是jps -l查看,进程还在,但是服务访问不了了,且因为cpu已经降下来了,使用jstack、jstat查看后,各线程也都正常,jvm内存统计也没有发现异常,GC次数肥肠高,但是因为系统运行很久了,以前导致的很高还是最近导致的很高,也不确定,至于哪个方法导致的,日志并没有记录清楚。
  但是隐约猜到是导出报表导致的,线上的报表导出功能最近使用的频率非常高,且数据量非常之大。
  于是,在测试环境,同数据量模拟了一下:

模拟生产环境,多次点击导出大数据量报表导致内存塞满,然后疯狂GC,CPU升高,页面无响应的问题。

    发现,在多个并发的大数据量导出的情况下,系统出现于生产环境一样的情况【本地开发没有那么多的数据量,因此一直没发现这个坑,以后要加大完善压力测试】,

打开jstat后,情况如下,一直在执行FGC
大数据量报表导出导致的生产页面卡死问题,OOM问题
然后日志输出了OOM的问题,以及引起的其他的方法执行的错误的报错。
大数据量报表导出导致的生产页面卡死问题,OOM问题
    经查询后发现,我们打的一次导出的数据量在二十几万的数据量,然后因为并发导出,且在导出生成对应的excel对象的过程中,对应的对象成倍生成,且这些对象在excel刷出到outputstream之前都会在内存中一直持有,导致内存一直在内存中引用,又释放不掉,导致内存撑爆。

   我们在导出的时候使用的是jxl工具,与POI一样都是一次刷出数据到输出流的。都不利于内存的释放,原本想分批次刷出数据的实验也失败了。jxl只会输出在第一次刷出之前的生成的excel的对象,且并不会释放之前的对象。

然后在查阅了文档之后发现,目前解决这个问题的方案,有以下几种:

  • 导出csv格式的数据
    缺点:数据格式不能保证
    优点:操作简单
  • 导出多个中间文件,将多个中间文件合并
    缺点:一个中间文件只能有一个工作表(sheet),合并文件也要耗时。
    优点:只要设定好每次请求数据大小,几乎不存在内存溢出问题。
  • 导出一个文件,循环分页请求数据,写入excel是分多个工作表(sheet)写入
    缺点:对于大量数据虽然利用循环分页的形式处理了一次性读取数据引发的内存溢出问题,但是,由于JXL在写入excel是,都是一次性写入的,所以还是回出现内存溢出问题。
    优点:能够实现10万条以内数据导出。
  • 导出一个Excel文件的xml形式,另存为.xls文件

    但是这些方式都不够友好且较为繁琐。

    然后看到了,阿里出品的一个EasyExcel工具,就可以将内存降低到很低的成都,因为它使用的是在服务器生成临时文件的形式来降低内存占用。

EasyExcel研究中。。。。。
未完待续。。。。