【发布时间】:2012-01-27 09:34:56
【问题描述】:
我正在调查 Jetty 6.1.26 的性能问题。 Jetty 似乎使用Transfer-Encoding: chunked,并且根据使用的缓冲区大小,在本地传输时这可能会非常慢。
我创建了一个小型 Jetty 测试应用程序,其中包含一个演示问题的 servlet。
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.nio.SelectChannelConnector;
import org.mortbay.jetty.servlet.Context;
public class TestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
final int bufferSize = 65536;
resp.setBufferSize(bufferSize);
OutputStream outStream = resp.getOutputStream();
FileInputStream stream = null;
try {
stream = new FileInputStream(new File("test.data"));
int bytesRead;
byte[] buffer = new byte[bufferSize];
while( (bytesRead = stream.read(buffer, 0, bufferSize)) > 0 ) {
outStream.write(buffer, 0, bytesRead);
outStream.flush();
}
} finally {
if( stream != null )
stream.close();
outStream.close();
}
}
public static void main(String[] args) throws Exception {
Server server = new Server();
SelectChannelConnector ret = new SelectChannelConnector();
ret.setLowResourceMaxIdleTime(10000);
ret.setAcceptQueueSize(128);
ret.setResolveNames(false);
ret.setUseDirectBuffers(false);
ret.setHost("0.0.0.0");
ret.setPort(8080);
server.addConnector(ret);
Context context = new Context();
context.setDisplayName("WebAppsContext");
context.setContextPath("/");
server.addHandler(context);
context.addServlet(TestServlet.class, "/test");
server.start();
}
}
在我的实验中,我使用了一个 128MB 的测试文件,该 servlet 返回到客户端,该客户端使用 localhost 进行连接。使用 Java 编写的简单测试客户端(使用URLConnection)下载这些数据需要 3.8 秒,这非常慢(是的,它是 33MB/s,听起来并不慢,除了这纯粹是本地和输入文件已缓存;它应该更快)。
现在这里变得奇怪了。如果我使用 wget 下载数据,它是一个 HTTP/1.0 客户端,因此不支持分块传输编码,它只需要 0.1 秒。这是一个更好的数字。
现在,当我将bufferSize 更改为 4096 时,Java 客户端需要 0.3 秒。
如果我完全删除对 resp.setBufferSize 的调用(它似乎使用 24KB 块大小),Java 客户端现在需要 7.1 秒,而 wget 突然变得同样慢!
请注意,我绝不是 Jetty 方面的专家。我在诊断 Hadoop 0.20.203.0 中的性能问题时偶然发现了这个问题,它使用 reduce 任务 shuffle,它使用 Jetty 传输文件的方式与缩减的示例代码非常相似,缓冲区大小为 64KB。
该问题在我们的 Linux (Debian) 服务器和我的 Windows 机器上以及 Java 1.6 和 1.7 上都重现,因此它似乎完全取决于 Jetty。
有谁知道这可能是什么原因造成的,如果有什么我可以做的吗?
【问题讨论】:
-
+1。我也观察到了这一点。但并没有真正得到好的解决方案。