提升Tomcat性能方法有很多种,使用NIO Connector和启用gzip压缩是其中两种。 NIO:Java New IO,使用了多路复用的技术,无疑要比普通的IO socket要高效。 gzip:对需要传输到前台的内容首先在内存中进行gzip压缩,这样可以大大的减少网络带宽占用。前提是前台的Accept-Encoding允许gzip。 但是,当同时配置了这两个时,会发现大于48KB的文件并没有进行压缩。 经查Tomcat源码,发现org.apache.catalina.servlets.DefaultServlet中:
[Java] 纯文本查看 复制代码 /**
* 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中,而是把文件的路径记录下来。
[Java] 纯文本查看 复制代码 /**
* 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内核内存。
[Java] 纯文本查看 复制代码
/**
* 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选项。
[XML] 纯文本查看 复制代码 <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
|