Question

J'ai écrit le serveur qui accepte les messages de connexion et de bombardement (~ 100 octets) à l'aide de Text Protocol et mon implémentation est capable d'envoyer des messages de bouclage 400K / SEC avec le client 3RT Party. J'ai choisi Netty pour cette tâche, SUSE 11 Realtime, JRockit RTS. Mais lorsque j'ai commencé à développer mon propre client basé sur Netty, je suis confronté à une réduction drastique du débit (de 400k à 1,3k msg / s). Le code du client est assez simple. Pourriez-vous, s'il vous plaît, donner un conseil ou montrer des exemples comment écrire un client beaucoup plus efficace. En fait, je vous soucie de plus de latence, mais j'ai commencé avec des tests de débit et je ne pense pas qu'il est normal d'avoir 1.5kmsg / sec sur la boucle. P.s. Le but du client ne reçoit que des messages du serveur et d'envoyer très rarement des headbits.

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

}

mise à jour. Sur le côté serveur, il existe un fil périodique qui écrit sur le canal client accepté. Et la chaîne devient bientôt non écrite. Mettre à jour N2. Ajout de la commande de MemoryawareExecutor dans le pipeline, mais il y a toujours un débit très faible (environ 4K msg / sec)

corrigé. Je mets exécuteur devant la pile de pipelines entière et cela a fonctionné!

Était-ce utile?

La solution

Si le serveur envoie des messages avec une taille fixe (~ 100 octets), vous pouvez définir le REVENEBufferSizePradictor sur le client Bootstrap, cela optimisera la lecture

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

Selon le segment de code que vous avez affiché: le fil de travailleur NIO du client fait tout dans le pipeline, il sera donc occupé à décoder et à exécuter les gestionnaires de messages.Vous devez ajouter un gestionnaire d'exécution.

Vous avez dit que, canal devenant non écrite du côté serveur, vous devrez peut-être régler les tailles de filigrane dans le serveur Bootstrap.Vous pouvez surveiller périodiquement la taille de la mémoire tampon d'écriture (Taille de la file d'attente d'écriture) et assurez-vous que le canal devient incroditable en raison de messages ne peut pas écrire sur le réseau.Cela peut être fait en ayant une classe UTIL comme ci-dessous.

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

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top