故障现象:

现场反馈,一个导出zip压缩包的下载功能,卡住847M不动了,滚动条不断提示,但速度为0,用的chrome浏览器。经,询问,另一个导出100多M的文件正常。

排查过程:

首先在家里进行了测试,模拟了1G的文件进行测试,一切正常。又模拟了2G的文件,显示内存溢出。但是传送文件是通过流传输的,通过apache 的IOUtils.copy复制到 Http Response的OutPutStream,不会占用太大内存。

怀疑1:

IOUtils.copy的代码有问题,经查看源码,是按4K缓存写入,没有问题,怀疑排除。

内存溢出的stack trace分析:

从输出异常栈中发现了ch.qos.logback.access.servlet.TeeServletOutputStream类,该项目使用了logback的access日志,经查看源码,果然是有问题。该类包装了ServletOutputStream,并重写了write(byte byteArray[], int offset, int length) 方法,把数据写入到ServletOutputStream之外,又写入了BtyeArrayOutputStream进行了缓存,用于日志输出。
        underlyingStream.write(byteArray, offset, length);
    baosCopy.write(byteArray, offset, length);
            下面是变量定义
            final ServletOutputStream underlyingStream;
    final ByteArrayOutputStream baosCopy;

解决方案:

关闭access日志,暂时没有实施,因为该日志是在parent项目里配置的,所以选择了修改个别代码,用真实的从包装类中获取真实的HttpServletResponse并写出文件流。

新问题:

解决了内存存溢出出问题,又出现了新的现象,文件超过1G大小就会中断,后台服务tomcat报timeout错误,但是网速好的情况下就没有这个错误。因为使用了nginx代理服务,所以是nginx缓存导致的超时问题,proxy_buffering off;把代理缓存关掉问题解决。

故障总结: