Transferencias lentas en Jetty con codificación de transferencia fragmentada en cierto tamaño de búfer

Estoy investigando un problema de rendimiento con Jetty 6.1.26. Jetty parece usarTransfer-Encoding: chunked, y dependiendo del tamaño del búfer utilizado, esto puede ser muy lento cuando se transfiere localmente.

He creado una pequeña aplicación de prueba de Jetty con un solo servlet que demuestra el problema.

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();
    }

}

En mi experimento, estoy usando un archivo de prueba de 128 MB que el servlet devuelve al cliente, que se conecta usando localhost. Descargar estos datos usando un cliente de prueba simple escrito en Java (usandoURLConnection) tarda 3,8 segundos, lo cual es muy lento (sí, es 33 MB / s, lo que no suena lento, excepto que esto es puramente local y el archivo de entrada se almacenó en caché; debería ser mucho más rápido).

Ahora aquí es donde se pone extraño. Si descargo los datos con wget, que es un cliente HTTP / 1.0 y, por lo tanto, no admite la codificación de transferencia fragmentada, solo tarda 0.1 segundos. Esa es una figura mucho mejor.

Ahora cuando cambiobufferSize a 4096, el cliente Java tarda 0,3 segundos.

Si elimino la llamada aresp.setBufferSize por completo (que parece usar un tamaño de fragmento de 24 KB), el cliente Java ahora tarda 7,1 segundos, ¡y wget es de repente igualmente lento!

Tenga en cuenta que no soy de ninguna manera un experto con Jetty. Me topé con este problema al diagnosticar un problema de rendimiento en Hadoop 0.20.203.0 con reducción de la combinación de tareas, que transfiere archivos usando Jetty de una manera muy similar al código de muestra reducido, con un tamaño de búfer de 64 KB.

El problema se reproduce tanto en nuestros servidores Linux (Debian) como en mi máquina Windows, y con Java 1.6 y 1.7, por lo que parece depender únicamente de Jetty.

¿Alguien tiene alguna idea de lo que podría estar causando esto, y si hay algo que pueda hacer al respecto?

Respuestas a la pregunta(6)

Su respuesta a la pregunta