基於後端生成大文件導出所產生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請求。
相關文章
相關標籤/搜索