用完文件描述符

时间:2015-09-13 17:54:18

标签: java sockets ssl netty nio

我正在使用基于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如何处理套接字耗尽/如何管理...?

0 个答案:

没有答案