Domanda

Ho scritto il server che accetta i messaggi di connessione e bombardieri (~ 100 byte) utilizzando il protocollo di testo e la mia implementazione è in grado di inviare i messaggi Loopback 400K/SEC con il client di 3RT Party. Ho scelto Netty per questo compito, SUSE 11 Realtime, Jrockit Rts. Ma quando ho iniziato a sviluppare il mio cliente in base a Netty I ha affrontato una drastica riduzione della throughput (da 400k a 1,3k msg/sec). Il codice del client è piuttosto semplice. Potresti, per favore, dare un consiglio o mostrare esempi come scrivere un cliente molto più efficace. In realtà, mi prendi più cura della latenza, ma ho iniziato con i test di throughput e non credo che sia normale avere 1,5 kmsg/sec su Loopback. Lo scopo del client PS sta ricevendo solo messaggi dal server e in modo molto raramente inviare cure.

Client.java

public class Client {

private static ClientBootstrap bootstrap;
private static Channel connector;
public static boolean start()
{
    ChannelFactory factory =
        new NioClientSocketChannelFactory(
                Executors.newCachedThreadPool(),
                Executors.newCachedThreadPool());
    ExecutionHandler executionHandler = new ExecutionHandler( new OrderedMemoryAwareThreadPoolExecutor(16, 1048576, 1048576));

    bootstrap = new ClientBootstrap(factory);

    bootstrap.setPipelineFactory( new ClientPipelineFactory() );

    bootstrap.setOption("tcpNoDelay", true);
    bootstrap.setOption("keepAlive", true);
    bootstrap.setOption("receiveBufferSize", 1048576);
    ChannelFuture future = bootstrap
            .connect(new InetSocketAddress("localhost", 9013));
    if (!future.awaitUninterruptibly().isSuccess()) {
        System.out.println("--- CLIENT - Failed to connect to server at " +
                           "localhost:9013.");
        bootstrap.releaseExternalResources();
        return false;
    }

    connector = future.getChannel();

    return connector.isConnected();
}
public static void main( String[] args )
{
    boolean started = start();
    if ( started )
        System.out.println( "Client connected to the server" );
}

}

ClientPipelineFactory.java

public class ClientPipelineFactory  implements ChannelPipelineFactory{

private final ExecutionHandler executionHandler;
public ClientPipelineFactory( ExecutionHandler executionHandle )
{
    this.executionHandler = executionHandle;
}
@Override
public ChannelPipeline getPipeline() throws Exception {
    ChannelPipeline pipeline = pipeline();
    pipeline.addLast("framer", new DelimiterBasedFrameDecoder(
              1024, Delimiters.lineDelimiter()));
    pipeline.addLast( "executor", executionHandler);
    pipeline.addLast("handler", new MessageHandler() );

    return pipeline;
}

}

MessageHandler.java
public class MessageHandler extends SimpleChannelHandler{

long max_msg = 10000;
long cur_msg = 0;
long startTime = System.nanoTime();
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
    cur_msg++;

    if ( cur_msg == max_msg )
    {
        System.out.println( "Throughput (msg/sec) : " + max_msg* NANOS_IN_SEC/(     System.nanoTime() - startTime )   );
        cur_msg = 0;
        startTime = System.nanoTime();
    }
}

@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
    e.getCause().printStackTrace();
    e.getChannel().close();
}

}

Aggiornare. Sul lato server c'è un thread periodico che scrive sul canale client accettato. E il canale diventa presto indeciso. Aggiorna N2. Aggiunto OrderedMeMoryaWareexecutor in pipeline, ma c'è ancora un throughput molto basso (circa 4K msg/sec)

Fisso. Ho messo l'esecutore di fronte all'intero stack della pipeline e ha funzionato!

È stato utile?

Soluzione

Se il server sta inviando messaggi con dimensioni fisse (~ 100 byte), è possibile impostare RECEVEBUFFERSIZEPRECTOR su Bootstrap client, questo ottimizzerà la lettura

bootstrap.setOption("receiveBufferSizePredictorFactory",
            new AdaptiveReceiveBufferSizePredictorFactory(MIN_PACKET_SIZE, INITIAL_PACKET_SIZE, MAX_PACKET_SIZE));

Secondo il segmento di codice che hai pubblicato: il thread di nio worker del client sta facendo tutto in pipeline, quindi sarà impegnato con la decodifica ed eseguire i gestori del messaggio. Devi aggiungere un gestore di esecuzione.

Hai detto che Channel sta diventando indesiderato dal lato server, quindi potresti dover regolare le dimensioni della filigrana nel bootstrap del server. È possibile monitorare periodicamente la dimensione del buffer di scrittura (dimensione della coda di scrittura) e assicurarti che il canale stia diventando indeciso a causa dei messaggi non può essere scritto nella rete. Può essere fatto avendo una lezione di util come sotto.

package org.jboss.netty.channel.socket.nio;

import org.jboss.netty.channel.Channel;

public final class NioChannelUtil {
  public static long getWriteTaskQueueCount(Channel channel) {
    NioSocketChannel nioChannel = (NioSocketChannel) channel;
    return nioChannel.writeBufferSize.get();
  }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top