Netty比Tomcat慢

我们刚刚完成了构建服务器以将数据存储到磁盘并使用Netty向前发送。 在负载测试期间,我们看到Netty每秒缩放到约8000条消息。 鉴于我们的系统,这看起来非常低。 对于基准测试,我们编写了一个Tomcat前端并运行相同的负载测试。 通过这些测试,我们每秒获得大约25,000条消息。

以下是我们的负载测试机的规格:

  • Macbook Pro四核心
  • 16GB的RAM
  • Java 1.6
  • 以下是Netty的负载测试设置:

  • 10个线程
  • 每个线程100,000条消息
  • Netty服务器代码(非常标准) - 服务器上的Netty管道是两个处理程序:一个FrameDecoder和一个处理请求和响应的SimpleChannelHandler。
  • 客户端JIO使用Commons Pool来共享和重用连接(池的大小与线程数相同)
  • 这里是Tomcat的负载测试设置:

  • 10个线程
  • 每个线程100,000条消息
  • Tomcat 7.0.16的默认配置使用Servlet来调用服务器代码
  • 客户端使用URLConnection而没有任何池
  • 我的主要问题是为什么在性能上有如此巨大的差异? Netty方面有什么明显的东西可以让它比Tomcat运行得更快?

    编辑:这里是主要的Netty服务器代码:

    NioServerSocketChannelFactory factory = new NioServerSocketChannelFactory();
    ServerBootstrap server = new ServerBootstrap(factory);
    server.setPipelineFactory(new ChannelPipelineFactory() {
      public ChannelPipeline getPipeline() {
        RequestDecoder decoder = injector.getInstance(RequestDecoder.class);
        ContentStoreChannelHandler handler = injector.getInstance(ContentStoreChannelHandler.class);
        return Channels.pipeline(decoder, handler);
      }
    });
    
    server.setOption("child.tcpNoDelay", true);
    server.setOption("child.keepAlive", true);
    Channel channel = server.bind(new InetSocketAddress(port));
    allChannels.add(channel);
    

    我们的处理程序是这样的:

    public class RequestDecoder extends FrameDecoder {
      @Override
      protected ChannelBuffer decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) {
        if (buffer.readableBytes() < 4) {
          return null;
        }
    
        buffer.markReaderIndex();
        int length = buffer.readInt();
        if (buffer.readableBytes() < length) {
          buffer.resetReaderIndex();
          return null;
        }
    
        return buffer;
      }
    }
    
    public class ContentStoreChannelHandler extends SimpleChannelHandler {
      private final RequestHandler handler;
    
      @Inject
      public ContentStoreChannelHandler(RequestHandler handler) {
        this.handler = handler;
      }
    
      @Override
      public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
        ChannelBuffer in = (ChannelBuffer) e.getMessage();
        in.readerIndex(4);
    
        ChannelBuffer out = ChannelBuffers.dynamicBuffer(512);
        out.writerIndex(8); // Skip the length and status code
    
        boolean success = handler.handle(new ChannelBufferInputStream(in), new ChannelBufferOutputStream(out), new NettyErrorStream(out));
        if (success) {
          out.setInt(0, out.writerIndex() - 8); // length
          out.setInt(4, 0); // Status
        }
    
        Channels.write(e.getChannel(), out, e.getRemoteAddress());
      }
    
      @Override
      public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
        Throwable throwable = e.getCause();
        ChannelBuffer out = ChannelBuffers.dynamicBuffer(8);
        out.writeInt(0); // Length
        out.writeInt(Errors.generalException.getCode()); // status
    
        Channels.write(ctx, e.getFuture(), out);
      }
    
      @Override
      public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) {
        NettyContentStoreServer.allChannels.add(e.getChannel());
      }
    }
    

    更新

    我已经设法让我的Netty解决方案在4,000 /秒之内。 几个星期前,我在连接池中测试客户端PING,作为防止闲置套接字的安全措施,但在开始负载测试之前,我忘记删除该代码。 每次从池中检出Socket(使用Commons Pool)时,此代码都有效地Ping了服务器。 我评论说这个代码出来了,现在我用Netty以21,000 /秒和Tomcat以25,000 /秒。

    虽然在Netty方面这是一个好消息,但我仍然比Netty少4000美元/秒。 如果有人对此感兴趣,我可以发布我的客户端(我认为我已排除但显然不是)。


    messageReceived方法使用可能被RequestHandler#handle阻塞的工作线程执行,该RequestHandler#handle可能正在忙于某些I / O工作。 您可以尝试在通道管道中添加一个OrderdMemoryAwareThreadPoolExecutor推荐 )来执行处理程序,或者尝试将您的处理程序工作分派给新的ThreadPoolExecutor,并将引用传递给套接字通道以便稍后将响应写回客户端。 例:

    @Override
    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {   
    
        executor.submit(new Runnable() {
            processHandlerAndRespond(e);        
        });
    }
    
    private void processHandlerAndRespond(MessageEvent e) {
    
        ChannelBuffer in = (ChannelBuffer) e.getMessage();
        in.readerIndex(4);
        ChannelBuffer out = ChannelBuffers.dynamicBuffer(512);
        out.writerIndex(8); // Skip the length and status code
        boolean success = handler.handle(new ChannelBufferInputStream(in), new ChannelBufferOutputStream(out), new NettyErrorStream(out));
        if (success) {
            out.setInt(0, out.writerIndex() - 8); // length
            out.setInt(4, 0); // Status
        }
        Channels.write(e.getChannel(), out, e.getRemoteAddress());
    } 
    
    链接地址: http://www.djcxy.com/p/95213.html

    上一篇: Netty slower than Tomcat

    下一篇: Java Netty load testing issues