我有一个简单的ECHO服务器和使用Netty编写的客户端。服务器和客户端位于同一台计算机上。我期待的平均延迟大约为几毫秒,但是,无论我尝试什么,我都不能将延迟降低到亚毫秒的持续时间。任何帮助将不胜感激。
更新:即使使用System.nanoTime,我也会看到延迟大约25-30毫秒。
EchoClient
import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.*;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jboss.netty.handler.execution.ExecutionHandler;
import org.jboss.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
public class EchoClient {
public static void main(String[] args) {
if (args.length != 1) {
System.err.println(String.format("usage: %s <num-msgs>", EchoClient.class.getCanonicalName()));
System.exit(1);
}
final long NUM_MSGS = Integer.parseInt(args[0]);
final EchoClientHandler echoClientHandler = new EchoClientHandler();
final ExecutionHandler e =
new ExecutionHandler(new OrderedMemoryAwareThreadPoolExecutor(4, 128 * 1024L, 128 * 1024L));
ChannelFactory factory =
new NioClientSocketChannelFactory(Executors.newCachedThreadPool(),
Executors.newCachedThreadPool());
ClientBootstrap bootstrap = new ClientBootstrap(factory);
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
@Override
public ChannelPipeline getPipeline() throws Exception {
return Channels.pipeline(new TestPayloadEncoder(),
new TestPayloadDecoder(),
e,
echoClientHandler);
}
});
bootstrap.setOption("tcpNoDelay", true);
bootstrap.setOption("keepAlive", false);
bootstrap.setOption("child.keepAlive", false);
bootstrap.setOption("sendBufferSize", 128 * 1024L);
bootstrap.setOption("receiveBufferSize", 128 * 1024L);
for (int i = 0; i < NUM_MSGS; i++) {
final InetSocketAddress serverAddr =
new InetSocketAddress("localhost", 8080);
bootstrap.connect(serverAddr).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture f) throws Exception {
if (f.isSuccess()) {
f.getChannel().write(new TestPayload());
}
}
});
}
while (echoClientHandler.numMsgs.get() < NUM_MSGS);
System.out.println(echoClientHandler.numMsgs);
System.out.println(echoClientHandler.aggTime);
System.out.println(String.format("mean transfer time: %.2fms",
((float) echoClientHandler.aggTime.get()) /
echoClientHandler.numMsgs.get()));
System.out.flush();
e.releaseExternalResources();
factory.releaseExternalResources();
}
}
EchoClientHandler
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
import java.util.concurrent.atomic.AtomicLong;
public class EchoClientHandler extends SimpleChannelHandler {
public final AtomicLong numMsgs = new AtomicLong(0);
public final AtomicLong aggTime = new AtomicLong(0);
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
long recvTime = System.currentTimeMillis();
TestPayload m = (TestPayload) e.getMessage();
aggTime.addAndGet(recvTime - m.getTime());
numMsgs.incrementAndGet();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
e.getCause().printStackTrace();
e.getChannel().close();
}
}
EchoServer的
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.execution.ExecutionHandler;
import org.jboss.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
public class EchoServer {
public static void main(String[] args) {
ChannelFactory factory =
new NioServerSocketChannelFactory(Executors.newFixedThreadPool(4),
Executors.newFixedThreadPool(32),
32);
ServerBootstrap bootstrap = new ServerBootstrap(factory);
final ExecutionHandler e =
new ExecutionHandler(new OrderedMemoryAwareThreadPoolExecutor(4, 128 * 1024L, 128 * 1024L));
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
@Override
public ChannelPipeline getPipeline() throws Exception {
return Channels.pipeline(e, new EchoServerHandler());
}
});
bootstrap.setOption("reuseAddr", true);
bootstrap.setOption("keepAlive", false);
bootstrap.setOption("child.reuseAddr", true);
bootstrap.setOption("child.soLinger", 0);
bootstrap.setOption("child.keepAlive", false);
bootstrap.setOption("child.tcpNoDelay", true);
bootstrap.setOption("child.sendBufferSize", 128 * 1024L);
bootstrap.setOption("child.receiveBufferSize", 128 * 1024L);
bootstrap.bind(new InetSocketAddress("localhost", 8080));
}
}
EchoServerHandler
import org.jboss.netty.channel.*;
public class EchoServerHandler extends SimpleChannelHandler {
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
e.getChannel().write(e.getMessage());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
e.getCause().printStackTrace();
e.getChannel().close();
}
}
TestPayload
import org.jboss.netty.buffer.ChannelBuffer;
import java.util.Date;
import java.util.Random;
public class TestPayload {
private static final int PREAMBLE_LEN = (Long.SIZE + Integer.SIZE) / 8;
private static final Random RNG;
static {
RNG = new Random();
RNG.setSeed(new Date().getTime());
}
private final int paddingLen;
private final byte[] padding;
private final long time;
public TestPayload() {
this(65536);
}
public TestPayload(int sizeInBytes) {
this.paddingLen = sizeInBytes;
this.padding = new byte[this.paddingLen];
RNG.nextBytes(this.padding);
this.time = System.currentTimeMillis();
}
private TestPayload(long time, int paddingLen, byte[] padding) {
this.paddingLen = paddingLen;
this.padding = padding;
this.time = time;
}
public long getTime() {
return this.time;
}
public void writeTo(ChannelBuffer buf) {
buf.writeLong(this.time);
buf.writeInt(this.paddingLen);
buf.writeBytes(this.padding);
}
public static TestPayload readFrom(ChannelBuffer buf) {
if (buf.readableBytes() < PREAMBLE_LEN) {
return null;
}
buf.markReaderIndex();
long time = buf.readLong();
int paddingLen = buf.readInt();
if (buf.readableBytes() < paddingLen) {
buf.resetReaderIndex();
return null;
}
byte[] padding = new byte[paddingLen];
buf.readBytes(padding);
return new TestPayload(time, paddingLen, padding);
}
public int getLength() {
return PREAMBLE_LEN + this.paddingLen;
}
答案 0 :(得分:0)
您是否在不同的JVM中运行客户端和服务器?如果是这样,那么跨JVM边界的测量时间并不像你想象的那么直接。例如,使用System.nanoTime()不一定按照oracle java doc:
工作只有在计算在Java虚拟机的同一实例中获得的两个此类值之间的差异时,此方法返回的值才会有意义。
假设您可以找到一种可靠的方法来测量JVM的时间,并且您的目标是隔离Netty客户端发送到Netty服务器所需的时间,然后简化您的用例以尽可能地隔离它。例如,在上面的代码中,您计算发送/接收65536字节数组的时间。从计时实验中删除它,以帮助找出瓶颈所在。
你从多少次跑步中收集时间?你是否排除了Netty本身的初始化时间(在计时之前在客户端/服务器之间运行一些消息)?
另外,如何调整配置影响性能?有很多旋钮可以调整(线程池大小,发送/接收buff大小等等)。
您使用的是什么版本的Netty,并且在您写完后可以选择强制刷新吗?
我没有看到EchoClient
的代码。您似乎复制/粘贴EchoClientHandler
代码所在的EchoClient
代码。