我使用文本协议(protocol)编写了接受连接和轰炸消息(~100 字节)的服务器,我的实现能够通过第 3 方客户端发送大约 400K/秒的环回消息。我为这项任务选择了 Netty、SUSE 11 RealTime、JRockit RTS。 但是当我开始基于 Netty 开发自己的客户端时,我面临着吞吐量的急剧下降(从 400K 下降到 1.3K msg/sec)。客户端的代码非常简单。请您提供建议或举例说明如何编写更有效的客户。实际上,我更关心延迟,但从吞吐量测试开始,我认为环回有 1.5Kmsg/sec 是不正常的。 附言客户端的目的只是从服务器接收消息,很少发送 heartbits。
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();
}
}
更新。在服务器端,有一个定期线程写入已接受的客户端 channel 。并且该 channel 很快变得不可写。 更新 N2。在管道中添加了 OrderedMemoryAwareExecutor,但仍然存在非常低的吞吐量(大约 4k msg/sec)
已修复。我将执行器放在整个管道堆栈的前面,结果成功了!
最佳答案
如果服务器以固定大小(~100 字节)发送消息,您可以将 ReceiveBufferSizePredictor 设置为客户端 Bootstrap ,这将优化读取
bootstrap.setOption("receiveBufferSizePredictorFactory",
new AdaptiveReceiveBufferSizePredictorFactory(MIN_PACKET_SIZE, INITIAL_PACKET_SIZE, MAX_PACKET_SIZE));
根据您发布的代码段:客户端的 nio 工作线程正在执行管道中的所有操作,因此它将忙于解码和执行消息处理程序。您必须添加一个执行处理程序。
您已经说过, channel 从服务器端变得不可写,因此您可能必须在服务器 Bootstrap 中调整水印大小。您可以定期监视写入缓冲区大小(写入队列大小)并确保 channel 变得不可写,因为消息无法写入网络。可以通过如下所示的 util 类来完成。
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();
}
}
关于Java Netty 负载测试问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8985389/