基于后端生成大文件导出所产生oom问题的思考

Posted 车牛皮糖

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于后端生成大文件导出所产生oom问题的思考相关的知识,希望对你有一定的参考价值。

背景

存在一个业务场景,通过前端点击事件,需要到Mongo数据库里面取数据并整理成excel表格并发送给前端,数据量没有破十万的时候,一切还是比较美妙的。但是导出的量继续增加时前端页面直接卡死,后端也产生oom报错

问题定位

直接先说结论,就是后端在拿到数据生成excel表格时,将查询到的所有的数据定义一次性写入由POI定义在内存中的一个临时excel文件从而导致了oom报错。

解决办法

为解决问题先研究(bai du)了一下Poi生成Excel文件的几种方式

HSSF:Excel97-2003版本,扩展名为.xls。一个sheet最大行数65536,最大列数256。
XSSF:Excel2007版本开始,扩展名为.xlsx。一个sheet最大行数1048576,最大列数16384。
SXSSF:是在XSSF基础上,POI3.8版本开始提供的支持低内存占用的操作方式,扩展名为.xlsx。
采用Hssf或者Xssf模式都会导致同样的问题产生,其根本原因是构造方式的不同
SXSSF在构造时,会设置一个默认值a,内存中最多只有a行数据,当超过这个数据时,就将内存之前的数据删除,并且会在硬盘中生成临时文件。不过也因为该特性,导致其生成数据的速度会比其他俩种方式慢,同时由于Excel版本兼容性是向下兼容。所以其实最优的方式是量大用SXSSF,量小用XSSF.

SXSSFWorkbook workbook= new SXSSFWorkbook(Int a);

新问题产生

刚刚有提到一点,SXSSF模式的生成Excel文件比较慢。这又产生了一个新问题,修改了模式后,在实际前后端交互的时候,前端发送请求过来,经常在等待后端将文件生成再回应的过程中逐渐失去耐心从而导致请求失败。

解决问题的几个思路

  1. 优化后端生成文件时间。
    直接开始硬性治疗,既然你后端处理速度慢就优化速度,例如优化Mango查询代码,使用多线程并发写Excel等等.
    该方案的优点是减少了对外的整体查询的时间。缺点是后端容易掉头发,而且多线程增加了开发和维护的难度;高并发压力转移到内部的服务器上,对其QPS响应提出了更高的要求。
  2. 将数据查询和下载的流程异步化。
    浏览器请求下载后,服务端立即返回报表的唯一标识Key同时开始远程查询数据,客户端可以凭借该Key查询报表的生成进度,报表完成后就可以下载;或者使用另一种方案,服务器在报表生成完成后通过一些渠道(如Long-Polling、WebSocket、即时通信软件、邮件等)通知客户端下载。
    该方案的优点是并发能力强,不会阻塞服务器的Web连接池。缺点是需要开发Key的CRUD操作和相应的UI;还需要在服务器端存储生成的报表文件。
  3. 服务端边生成文件,浏览器边下载报表。
    就像下载大文件一样,浏览器不断开和服务器的Http连接,同时服务器不断向浏览器追加Http体数据直到报表生成结束。
    该方案的优点是开发难度低、速度快。缺点是数据查询是单线程的,速度较慢;而且文件下载会一直占用服务器的Web连接池,如果并发下载量较大可能会阻塞其他的Http请求。

以上是关于基于后端生成大文件导出所产生oom问题的思考的主要内容,如果未能解决你的问题,请参考以下文章

模板引擎的思考

内存溢出与内存泄漏

Alibaba工具型技术系列「EasyExcel技术专题」摒除OOM!让你的Excel操作变

SpringBoot 之 PDF大文件分片加载(后端)

Android 逆向Android 系统文件分析 ( /proc/pid 进程号对应进程目录 | oom_adj | maps | smaps | mem | task | environ )(代码片

Android 逆向Android 系统文件分析 ( /proc/pid 进程号对应进程目录 | oom_adj | maps | smaps | mem | task | environ )(代码片