2011-03-28 14 views
8

Estoy trabajando a través del example Netty HTTP Client code para realizar solicitudes http dentro de un entorno concurrente y enhebrado.HTTP muy concurrente con Netty y NIO

Sin embargo, mi sistema se rompe por completo (con una serie de excepciones) a un rendimiento bastante bajo.

En casi pseudo-código:

ClientBootstrap bootstrap = new ClientBootstrap(new NioClientSocketChannelFactory()) 
bootstrap.setPipelineFactory(new HttpClientPipelineFactory()); 

ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); 
Channel channel = future.awaitUninterruptibly().getChannel(); 

HttpRequest request = new DefaultHttpRequest(); 
channel.write(request); 

En el ejemplo, para hacer una solicitud creo un ClientBootstrap, y desde allí (a través de unos aros) un canal para escribir el HTTPRequest.

Todo esto funciona y es bueno.

Sin embargo, en una situación concurrente, ¿cada solicitud debe pasar por los mismos aros? Creo que eso es lo que está rompiendo las cosas para mí en este momento. ¿Debo volver a utilizar la conexión o estructurar a mi cliente de una manera completamente diferente?

También: Estoy haciendo esto en Clojure, si eso hace alguna diferencia.

+0

tal vez debería usar https://github.com/ztellman/aleph? – PheliX

+0

¿Tiene experiencia con aleph? He intentado con otro cliente http async clojure, pero no funciona a los niveles de rendimiento que necesito mantener. –

Respuesta

7

No, estás haciendo las cosas bien. Sin embargo, debe mantener una referencia a su instancia Channel. Una vez que tienes ese canal, mientras esté abierto, no necesitas crear otro bootstrap. (Si eso es lo que está haciendo.)

Esto es lo que he usado en un reciente proyecto:

ClientConnection clase(constructor)

// Configure the client. 
bootstrap = new ClientBootstrap(
    new NioClientSocketChannelFactory(
     Executors.newCachedThreadPool(), 
     Executors.newCachedThreadPool() 
    ) 
); 

// Set up the pipeline factory. 
bootstrap.setPipelineFactory(
    new ChannelPipelineFactory() { 
     public ChannelPipeline getPipeline() throws Exception { 
      return Channels.pipeline(
       // put your handlers here 
      ); 
     } 
    } 
); 

ClientConnection.connect clase (principal de la serie, int puerto)

if (isConnected()) { 
    throw new IllegalStateException("already connected"); 
} 

// Start the connection attempt. 
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); 

channel = future.awaitUninterruptibly().getChannel(); 

// Wait until the connection is closed or the connection attempt fails. 
channel.getCloseFuture().addListener(new ChannelFutureListener() { 
    @Override 
    public void operationComplete(ChannelFuture future) throws Exception { 
     new Thread(new Runnable() { 
      public void run() { 
       // Shut down thread pools to exit 
       // (cannot be executed in the same thread pool! 
       bootstrap.releaseExternalResources(); 

       LOG.log(Level.INFO, "Shutting down"); 
      } 
     }).start(); 
    } 
}); 

Así que, básicamente, solo guardo una referencia a bootstrap y channel, sin embargo, el primero no se usa fuera de estas líneas de código.

Nota: solo debe ejecutar bootstrap.releaseExternalResources(); una vez, cuando la aplicación está saliendo. En mi caso, el cliente envía algunos archivos, luego cierra el canal y sale.

Una vez que tenga una instancia de Channel conectada, solo necesita usar esa hasta que la cierre nuevamente. Una vez que esté cerrado, puede recuperar el bootstrap para crear un nuevo Channel nuevamente.

Personalmente, me parece que Netty es un poco difícil de entender al principio, pero una vez que entiendes cómo funciona, es simplemente el mejor framework de NIO en Java. IMO.

+3

'bootstrap' también será útil si desea establecer otra conexión y utilizar la maquinaria existente (hilos subyacentes de trabajo de Netty NIO). –