Nginx请求超时

最近用户老说下载失败,我试了一下,果然出现了问题,记录一下这几个问题:

首先浏览器的提示是: Nginx 504 Gateway Time-out

这个问题其实不是浏览器和Nginx请求超时,而是Nginx和你的应用服务器之间请求超时,也就是和我的Tomcat。

error.log的错误信息如下:

upstream timed out (110: Connection timed out) while reading response header from upstream

网上看了很多基本上都PHP的,后来发现要设置一下proxy的属性:

proxy_connect_timeout 300;
proxy_read_timeout 300;
proxy_send_timeout 300;

文章地址:http://baiqiuyi.com/linux/upstream-timed-out-110-connection-timed-out-while-reading-response-header-from-upstream.html

设置后还发现一个问题,有的还是存在问题,最后我去看了一下磁盘信息,发现写入的时候非常慢。
于是我找到了我的压缩方法,认真一看后发现了问题,原来的压缩方法:

try {
    zos = new ZipOutputStream(out);
    zos.setEncoding("UTF-8");
    for (File file : files) {
        if(file != null && file.exists() && file.isFile()) {
            FileInputStream fis = new FileInputStream(file);
            ZipEntry entry = new ZipEntry(file.getName());
            entry.setUnixMode(644); // linux乱码
            zos.putNextEntry(entry);
            int len;
            while ((len = fis.read()) != -1) {
                zos.write(len);
            }
            fis.close();
            zos.flush();
        }
    }
} catch (Exception e) {
    e.printStackTrace();
} finally {
    IOUtils.closeQuietly(zos);
    IOUtils.closeQuietly(out);
}

然后我改了一下,改了一下缓冲的大小,立马快了几十倍:

try {
    zos = new ZipOutputStream(out);
    zos.setEncoding("UTF-8");
    for (File file : files) {
        if(file != null && file.exists() && file.isFile()) {
            FileInputStream fis = new FileInputStream(file);
            ZipEntry entry = new ZipEntry(file.getName());
            entry.setUnixMode(644); // linux乱码
            zos.putNextEntry(entry);
            int len;
            byte[] bs = new byte[1024];
            while ((len = fis.read(bs)) != -1) {
                zos.write(bs, 0, len);
            }
            fis.close();
            zos.flush();
        }
    }
} catch (Exception e) {
    e.printStackTrace();
} finally {
    IOUtils.closeQuietly(zos);
    IOUtils.closeQuietly(out);
}

顺便这里在记录一些问题:

an upstream response is buffered to a temporary file /var/cache/nginx/proxy_temp/7/29/0000006297 while reading upstream, client

这个原因是因为nginx的缓冲区设置比较小,修复方法:

proxy_buffer_size 4k;
proxy_buffers 64 32k;

还有下面一个错误:

 org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalStateException: getOutputStream() has already been called for this response
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:948)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:827)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:729)
    at org.apache.catalina.core.ApplicationDispatcher.doInclude(ApplicationDispatcher.java:585)
    at org.apache.catalina.core.ApplicationDispatcher.include(ApplicationDispatcher.java:524)
    at org.apache.catalina.core.StandardHostValve.custom(StandardHostValve.java:450)
    at org.apache.catalina.core.StandardHostValve.throwable(StandardHostValve.java:400)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:185)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:76)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:90)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:515)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1012)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:642)
    at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:223)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1597)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1555)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalStateException: getOutputStream() has already been called for this response
    at org.apache.catalina.connector.Response.getWriter(Response.java:537)
    at org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:214)
    at javax.servlet.ServletResponseWrapper.getWriter(ServletResponseWrapper.java:105)
    at org.springframework.web.servlet.view.freemarker.FreeMarkerView.processTemplate(FreeMarkerView.java:366)
    at org.springframework.web.servlet.view.freemarker.FreeMarkerView.doRender(FreeMarkerView.java:283)
    at org.springframework.web.servlet.view.freemarker.FreeMarkerView.renderMergedTemplateModel(FreeMarkerView.java:233)
    at org.springframework.web.servlet.view.AbstractTemplateView.renderMergedOutputModel(AbstractTemplateView.java:167)
    at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:264)
    at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1208)
    at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:992)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:939)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936)
    ... 23 more

这个错误困扰了我很久了,一直没有找到原因,后来发现原来response.getOutputStream();response.getWriter();这两个方法不能同时用,我估计freemarker输出html的时候使用的response.getWriter()这个方法,所以在代码里面使用了response.getOutputStream();都会出现这个问题,如果是返回页面的最好不要用,如果是输出图片就没有返回值的方法,ajax也是没问题的。