我正在使用基于Netty的测试人员应用程序作为客户端运行服务器性能测试。连接通过SSL套接字,我发送注册,服务器启动流数据。所以我尝试创建服务器可以处理的连接数。
我在我的测试仪上达到了大约4000个套接字,直到它(客户端操作系统进程)由于打开的套接字太多而耗尽了文件描述符。如果我从Netty收到正确的错误消息,这将没有问题。但是,Netty给我的唯一东西是:java.nio.channels.ClosedChannelException。这甚至没有堆栈跟踪。
在使用调试器进行各种运行后,我认为这是由于io.netty.handler.ssl.SslHandler处理以下错误:
private static final ClosedChannelException CHANNEL_CLOSED = new ClosedChannelException();
static {CHANNEL_CLOSED.setStackTrace(EmptyArrays.EMPTY_STACK_TRACE);}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
// Make sure to release SSLEngine,
// and notify the handshake future if the connection has been closed during handshake.
setHandshakeFailure(ctx, CHANNEL_CLOSED);
super.channelInactive(ctx);
}
最后,这会导致抛出ClosedChannelException而没有堆栈跟踪。如果我在调试器上运行它并在Netty中设置断点,这似乎是由于SSL握手超时。我相信这个超时是由于文件描述符耗尽。不知道为什么Netty会把它视为超时。
我之所以认为它耗尽了文件描述符,是因为此测试的早期版本在系统中获得了太多打开文件的异常。但是,在减少代码中其他地方的文件使用后,它现在得到了这么远,但我不再收到有意义的错误消息。如果我同时运行其他软件并在Netty挂起时保持打开文件,我仍然会收到太多打开文件的错误。
我想知道是否有一些技巧可以让Netty正确报告失败的实际原因?
以下是主要的相关客户端初始化代码:
private static final EventLoopGroup group = new NioEventLoopGroup();
public SSLClientNetty() throws Exception {
SSLContext context = SSLContext.getInstance("TLS");
context.init(keyManagers, trustManagers, null);
SSLEngine sslEngine = context.createSSLEngine();
sslEngine.setUseClientMode(true);
SslHandler sslHandler = new SslHandler(sslEngine);
//this is the time Netty waits before throwing the ClosedChannelException after reaching file limit
sslHandler.setHandshakeTimeoutMillis(5000);
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new MyInitializer(sslHandler));
ch = b.connect("localhost", 5555).sync().channel();
} catch (Exception e) {
log.error("Error connecting to server", e);
throw new RuntimeException("Error connecting to server", e);
}
}
MyInitializer的主要相关代码:
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(sslHandler);
ch.pipeline().addLast("bytesEncoder", new ByteArrayEncoder());
ch.pipeline().addLast(new MyDecoder());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
super.exceptionCaught(ctx, cause);
log.error("Error in initializing connection", cause);
}
在MyDecoder中,只是为了确保我也记录任何异常:
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
super.exceptionCaught(ctx, cause);
log.error("Error in decoder", cause);
throw new RuntimeException("Error in decoder", cause);
}
测试人员创建连接的主循环:
while (true) {
SSLClientNetty client = new SSLClientNetty();
client.register();
Thread.sleep(10);
}
现在错误消息只有这个:
4000:...................java.nio.channels.ClosedChannelException
测试人员为每个成功打开的连接打印一个点,并以Netty抛出ClosedChannelException而没有堆栈跟踪结束(如上所述)。
因此,只是为了重新迭代,我希望得到一个更好的错误报告,以确定实际导致连接失败的原因。并了解Netty如何处理套接字耗尽/如何管理...?