记一次内部测试平台的性能故障分析排查过程--excel文件太大导致读取文件失败

第一次报障

1、执行用例总是提示获取到dataprovider获取到的Object[][]为空

Object[][]为空.png

2、在本地调试并不能每次复现,重启一下服务器就能好。没有明显的报错日志。

第一次问题定位

1、运行调试,发现总是读取表格文件的这一步

读取表格文件.png

发现这里的错误只捕获了IOException。于是在抛出错误的时候,将IOException调整为Exception

修改为捕获Exception.png

一开始捕捉到的是一个NullPointException

于是第一次的解决方案是:加多一个NullPointException。

加多一个NullPointException.png

由于本地运行正常,所以就上线了并告诉大家修复了问题。

第二次报障

上线后,测试同学小美仍然反馈出执行不了的问题,然后重启之后,原本的文件就能够正常执行了,但是再上传一个新文件执行,同样会报这个错。

第二次问题定位

1、此时发现测试同学小美所使用的表格文件特别大。正常情况下只有200k左右的用例文件,执行有问题的文件居然高达4M。

文件很大.png

考虑可能是4M的文件解析带来的问题,

于是在抛出错误的时候,再次调整为Exception

修改为捕获Exception.png

【重现步骤】

1、先执行一次4M的文件的用例

2、执行完成后再上传一个4M的用例(上传用例过程在线上执行,直连线上的数据库,然后复制一份用例文件到本地执行)

3、使用新的文件执行用例

此时明确发现,是由于OOM内存溢出导致的问题

OOM.png

于是打开jprofiler进行分析

1、第一次运行4m文件

第一次运行4M.png

再上传一个新的4m文件,然后执行用例(上传用例过程在线上执行,直连线上的数据库,然后复制一份用例文件到本地执行)。

直接内存占用高达1.62G,GC100%运行,CPU未出现过载,所以性能瓶颈点主要在内存。判断可能存在内存泄漏。

第二次运行4M.png
GC活动.png
cpu占用.png

另外还发现:超时还可能导致无法连接上zk,导致后续的测试无法继续执行

[图片上传失败...(image-5f70f9-1548245913902)]

但从上面只能定位到可能是内存泄漏,但未能定位到是什么原因导致,于是我们转向Live Memory

打开jprofiler的Live Memory,执行如下步骤:

1、先执行两个普通大小用例文件的用例,观察内存中那类占用比较多--此时没发现什么异常(所以没有截图)

2、再执行一个4M大小的用例。

发现下图中AttrXobj、ElementXobj暴涨。几乎占据了图中80%以上的量。

(后续还执行了第二个4M文件,但由于直接跑崩了所以没有收集到第二次4M文件执行的内存数据)

Live Memory.png

然后搜索AttrXobj(搜索AttrXobj),得知该类与XSSFWorkbook有关。

搜索结果.png

并且

1、从第一条搜索结果可知(SXSSFWorkbook & XSSFWorkbook 效率比拼)XSSFWorkbook本身在大数据量下存在性能问题。

image.png

2、在第四条记录上看到了非常类似情况:记一次FullGC的排查

image.png

所以基本上定位到问题是处在我们ExcelUtils中用到的XSSFWorkbook对象身上。

最终解决思路

第一个:像记一次FullGC的排查这样限制用户上传文件大小

思考:虽然该方法成本最低。但由于用例文件可能会存放多个sheet,即使单个sheet数据量不超过100k,整个excel文件的总size无法预估,且无法解决根本问题,所以先不采取这个方法。

第二个:检查内存泄漏点,解决内存泄漏

从下图中可发现,黄框部分是执行完GC之后的内存占用情况,随着用例执行而增多。

内存占用趋势.png
读取表格方法的源码.png

结合两图可以定位到是XSSFWorkbook的问题。那我们关注到调用这个类的方法上。

从下图中可以看到,在方法中,有一个FileInputStream对象,但是读取了之后没有对应的关闭方法。

excelWBook、excelWsheet这两个对象是一个静态对象,在执行完操作之后,却没有进行对象的清空。可能会一直存活着。

从代码里也可以看到一个点:excelWBook这个变量是一个静态变量,第一次读取4M文件后,未被释放。然后到了第二次读取的时候,

excelWBook = new XSSFWorkbook(ExcelFile)

先执行new XSSFWorkbook(ExcelFile) 再将new出来的对象赋值给excelWBook。所以 此时 excelWBook占用一波内存,new XSSFWorkbook(ExcelFile)又要占用一波内存,导致直接内存爆掉了。

修复前内存情况.png

【优化点】

1、将excelWSheet、excelWBook、cell从静态变量改为实例变量,释放内存。

2、加一个try-finally/try-with-resource关闭FileInputStream文件流。

3、使用SXSSFWorkbook替换XSSFWorkbook,降低内存开销。

参考文档

IntelliJ IDEA集成JProfiler,入门教程

SXSSFWorkbook & XSSFWorkbook 效率比拼

记一次FullGC的排查

修复结果

多次执行4M大小的文件响应正常且内存稳定。

修复后内存情况.png

修复后的关键源码

public static Object[][] getTableArray(String FilePath, String SheetName, int totalCols, Boolean isWithTitleRow) throws IOException {
    String[][] tabArray = (String[][])null;
    FileInputStream excelFile = null;

    try {
        excelFile = new FileInputStream(FilePath);
        XSSFWorkbook excelWBook = new XSSFWorkbook(excelFile);
        XSSFSheet excelWSheet = excelWBook.getSheet(SheetName);
        int startRow = 0;
        int startCol = 0;
        int lastRowNum = excelWSheet.getLastRowNum();
        int lastCol = totalCols - 1;
        if (isWithTitleRow) {
            startRow = 1;
        }

        int totalRow = getRealRowNum(excelWSheet, startRow, lastRowNum, startCol, lastCol);
        if (isWithTitleRow) {
            tabArray = new String[totalRow][totalCols];
        } else {
            tabArray = new String[totalRow + 1][totalCols];
        }

        for(int currentRow = startRow; currentRow <= totalRow; ++currentRow) {
            for(int currentCol = startCol; currentCol <= lastCol; ++currentCol) {
                tabArray[currentRow - startRow][currentCol] = getCellData(excelWSheet, currentRow, currentCol);
            }
        }
    } finally {
        if (excelFile != null) {
            excelFile.close();
        }

    }

    return tabArray;
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容