gzip的详细配置请查看笔记:tomcat的gzip压缩配置及优化效果对比


提升Tomcat性能方法有很多种,使用NIO Connector和启用gzip压缩是其中两种。

NIO:Java New IO,使用了多路复用的技术,无疑要比普通的IO socket要高效。

gzip:对需要传输到前台的内容首先在内存中进行gzip压缩,这样可以大大的减少网络带宽占用。前提是前台的Accept-Encoding允许gzip。

但是,当同时配置了这两个时,会发现大于48KB的文件并没有进行压缩。

经查Tomcat源码,发现org.apache.catalina.servlets.DefaultServlet中:

/** 
     * Check if sendfile can be used. 
     */  
    protected boolean checkSendfile(HttpServletRequest request,  
                                  HttpServletResponse response,  
                                  CacheEntry entry,  
                                  long length, Range range) {  
        if ((sendfileSize > 0)  
            && (entry.resource != null)  
            && ((length > sendfileSize) || (entry.resource.getContent() == null))  
            && (entry.attributes.getCanonicalPath() != null)  
            && (Boolean.TRUE == request.getAttribute("org.apache.tomcat.sendfile.support"))  
            && (request.getClass().getName().equals("org.apache.catalina.connector.RequestFacade"))  
            && (response.getClass().getName().equals("org.apache.catalina.connector.ResponseFacade"))) {  
            request.setAttribute("org.apache.tomcat.sendfile.filename", entry.attributes.getCanonicalPath());  
            if (range == null) {  
                request.setAttribute("org.apache.tomcat.sendfile.start", new Long(0L));  
                request.setAttribute("org.apache.tomcat.sendfile.end", new Long(length));  
            } else {  
                request.setAttribute("org.apache.tomcat.sendfile.start", new Long(range.start));  
                request.setAttribute("org.apache.tomcat.sendfile.end", new Long(range.end + 1));  
            }  
            return true;  
        } else {  
            return false;  
        }  
    }  
此处的sendfileSize = 48*1024,默认值为48KB,可以发现,当文件大小大于48KB时,Tomcat并未马上将内容写回到output中,而是把文件的路径记录下来。

/** 
     * Serve the specified resource, optionally including the data content. 
     * 
     * @param request The servlet request we are processing 
     * @param response The servlet response we are creating 
     * @param content Should the content be included? 
     * 
     * @exception IOException if an input/output error occurs 
     * @exception ServletException if a servlet-specified error occurs 
     */  
    protected void serveResource(HttpServletRequest request,  
                                 HttpServletResponse response,  
                                 boolean content)  
        throws IOException, ServletException {  
  
            ......  
  
            // Copy the input stream to our output stream (if requested)  
            if (content) {  
                try {  
                    response.setBufferSize(output);  
                } catch (IllegalStateException e) {  
                    // Silent catch  
                }  
                if (ostream != null) {  
                    if (!checkSendfile(request, response, cacheEntry, contentLength, null))  
                        copy(cacheEntry, renderResult, ostream);  
                } else {  
                    copy(cacheEntry, renderResult, writer);  
                }  
            }  
              
            ......  
  
    }  
并在Http11Processor的process方法的最后一部分,把文件内容以FileChannel的形式写回到前台,不需要先把文件内容先读到用户内存->压缩->写回socket内核内存。
/** 
     * Process pipelined HTTP requests using the specified input and output 
     * streams. 
     * 
     * @throws IOException error during an I/O operation 
     */  
    public SocketState process(NioChannel socket)  
        throws IOException {  
          
         ......  
            // Do sendfile as needed: add socket to sendfile and end  
            if (sendfileData != null && !error) {  
                KeyAttachment ka = (KeyAttachment)socket.getAttachment(false);  
                ka.setSendfileData(sendfileData);  
                sendfileData.keepAlive = keepAlive;  
                SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector());  
                //do the first write on this thread, might as well  
                openSocket = socket.getPoller().processSendfile(key,ka,true,true);  
                break;  
            }  
        ......  
  
    }  

这种NIO底层读写channel的形式避免了读取到用户内存的开销,也可以提升性能。

目前,尚不清楚使用NIO快,还是gzip较快,有待测试。

如果在使用NIO的同时还一定要用gzip,可以关闭NIO Connector的useSendFile选项。

<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"  
               connectionTimeout="20000"   
               redirectPort="8443"  
                useSendfile="false"  
                compression="on"   
                compressionMinSize="2048"   
                noCompressionUserAgents="gozilla, traviata"   
                compressableMimeType="text/html,text/xml,text/javascript" />  

参考地址:http://tomcat.apache.org/tomcat-6.0-doc/config/http.html




浏览 930 评论 0 赞 0 砸 0 标签: 优化 tomcat
评论
还可以再输入500个字

请您注意

·自觉遵守:爱国、守法、自律、真实、文明的原则
·尊重网上道德,遵守《全国人大常委会关于维护互联网安全的决定》及中华人民共和国其他各项有关法律法规
·严禁发表危害国家安全,破坏民族团结、国家宗教政策和社会稳定,含侮辱、诽谤、教唆、淫秽等内容的作品
·承担一切因您的行为而直接或间接导致的民事或刑事法律责任
·您在NoteShare上发表的作品,NoteShare有权在网站内保留、转载、引用或者删除
·参与本评论即表明您已经阅读并接受上述条款