Я исследую проблему с производительностью Jetty 6.1.26. Jetty, похоже, использует Transfer-Encoding: chunked
, и в зависимости от используемого размера буфера это может быть очень медленно при локальной передаче.
Я создал небольшое тестовое приложение Jetty с одним сервлетом, демонстрирующим проблему.
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();
}
}
В моем эксперименте я использую тестовый файл объемом 128 МБ, который сервлет возвращает клиенту, который подключается с помощью localhost. Загрузка этих данных с использованием простого тестового клиента, написанного на Java (с использованием URLConnection
), занимает 3,8 секунды, что очень медленно (да, это 33 МБ / с, что не звучит медленно, за исключением того, что это чисто локально и входной файл был кэширован, это должно быть намного быстрее).
Теперь вот где это становится странным. Если я загружаю данные с помощью wget, который является клиентом HTTP / 1.0 и поэтому не поддерживает частичное кодирование передачи, это займет всего 0,1 секунды. Это намного лучше.
Теперь, когда я меняю bufferSize
на 4096, клиент Java занимает 0,3 секунды.
Если я полностью удаляю вызов resp.setBufferSize
(который, похоже, использует размер фрагмента 24 КБ), клиент Java теперь занимает 7,1 секунды, а wget внезапно становится таким же медленным!
Пожалуйста, обратите внимание, что я никоим образом не эксперт по Jetty. Я наткнулся на эту проблему при диагностике проблемы с производительностью в Hadoop 0.20.203.0 с уменьшенным перетасованием задач, который передает файлы с использованием Jetty так же, как сокращенный пример кода, с размером буфера 64 КБ.
Проблема воспроизводится как на наших серверах Linux (Debian), так и на моем компьютере с Windows, а также на Java 1.6 и 1.7, поэтому, похоже, она зависит исключительно от Jetty.
Кто-нибудь знает, что может быть причиной этого, и если я что-то могу с этим поделать?