当前位置: 首页 > 知识库问答 >
问题:

Netty比Tomcat慢

宿丰
2023-03-14

我们刚刚构建了一个将数据存储到磁盘的服务器,并使用Netty进行了前端。在负载测试期间,我们看到Netty扩展到每秒大约8,000条消息。考虑到我们的系统,这看起来非常低。作为基准测试,我们编写了一个Tomcat前端并运行相同的负载测试。通过这些测试,我们每秒收到大约25,000条消息。

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

  • Macbook Pro四核
  • 16GB的RAM
  • Java1.6

以下是Netty的负载测试设置:

  • 10个线程

以下是Tomcat的负载测试设置:

  • 10个线程
  • 每线程100000条消息
  • 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解决方案控制在4000/s以内。几周前,我在连接池中测试客户端PING,作为对空闲套接字的安全防护,但在开始负载测试之前,我忘了删除该代码。每次从池(使用Commons池)签出套接字时,该代码都会有效地ping服务器。我把代码注释掉了,我现在用Netty得到了21000/秒,用Tomcat得到了25000/秒。

虽然,这对Netty来说是个好消息,但我在Netty上的速度仍然比Tomcat低4000/秒。如果有人有兴趣看到,我可以发布我的客户端(我认为我已经排除了,但显然没有)。

共有1个答案

萧浩漫
2023-03-14

方法messageReceived是使用一个工作线程执行的,该工作线程可能被RequestHandler#handle阻塞,该工作线程可能忙于执行一些输入/输出工作。您可以尝试向通道管道中添加一个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());
} 
 类似资料:
  • 问题内容: 我目前正在开始新的应用开发。应用程序设计师坚持认为我们使用 JBoss5 是因为它“更好”。是否有人对“更好”有更广泛的定义(如果如此)? 我有在具有大量用户负载的大规模应用程序中使用 Tomcat5 和6的经验,并且它处理得很好(IMHO)。两者都将在相同的硬件条件下(如果实现很重要)在 RedHat6 上运行。 提前致谢 问题答案: 说任何工具或框架都只是“更好”是可笑的。它总是取

  • 我正在运行一个spring boot WebFlux应用程序,通常该应用程序运行在Netty嵌入式服务器之上。相反,我正在运行一个tomcat实例,我试图从我的pom中排除tomcat,但仍然遇到同样的问题。 所以我想通过运行Netty而不是Tomcat来解决这个问题。 这是我的pom依赖项:

  • Netty是一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。 也就是说,Netty 是一个基于NIO的客户、服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用。Netty相当简化和流线化了网络应用的编程开发过程,例如,TCP和UDP的socket服务开发

  • 在深入研究我的问题时,解释了atg gRpc在netty失败中使用SunPKCS11进行TLS客户端身份验证,我更改了netty-tcnative-boringssl的版本。我房子里的罐子。Gradle来自 到 导致: +---io.netty:netty-tcnative-boringssl-static:+->2.0.1.final 之所以这样做,是因为根据Netty的javadoc方法也适用

  • 在阅读了一些关于如何在使用Webflux时摆脱Tomcat的文章之后,我仍然无法使用Netty作为Tomcat的替代品。 因为这是一个涉及不同模块的项目,有一个父pom等。我将在这里发布repo的链接:https://github.com/deviad/clarity 让我知道如果有更多的文件等,你想让我复制粘贴在这里,以便遵守这样的政策。 我感兴趣的模块是clarity-transaction-

  • 问题内容: 尽管我的业务逻辑没有问题,但事实证明我没有使用Netty 。更新要使用的测试代码后,我遇到了IllegalReferenceCountException的无尽循环。我承认对Netty还是陌生的,但这并不能证明在手动分配和释放资源的日子里回来。创建GC就是为了避免这种混乱。迪斯科,有人吗?那贝尔底呢? 我不断得到: 问题答案: 工作代码: 该代码可能更简洁一些,但是适用于Spring b