当前位置:  开发笔记 > 前端 > 正文

Netty应用程序优化

如何解决《Netty应用程序优化》经验,为你挑选了1个好方法。

我正在编写一个基于Netty的本地HTTP服务器.当我进行压力测试时,我限制在400个请求/秒.

要优化我的服务器,我已经写了基于Netty的一个简单的服务器,只是发送的"Hello World"的客户端,我发起了一个压力测试与加特林2,和与此服务器,我已经得到了同样的结果(限制为400 req/s).

我使用Yourkit进行性能分析,没有额外的GC活动,我的开放/关闭套接字限制为480个套接字/秒.

我使用MacBook Pro,4核,16 GB RAM,我使用Netty 4.1.

我很惊讶地限制在400 req/s,因为其他基准测试的结果显示> 20 000 req/s或更多.我知道有硬件限制,但400 req/s,在4核+ 16 GB Ram上发送"hello World"非常低.

提前感谢您的帮助,我不知道从哪里开始优化我的Netty代码.

是否有任何优化Netty的具体指导方针?

这是我的hello world服务器的源代码,后跟我的连接的处理程序:

public class TestServer {

    private static final Logger logger = LogManager.getLogger("TestServer");

    int nbSockets = 0 ;

    EventLoopGroup pool = new NioEventLoopGroup() ;

    private void init(int port) {

        EventLoopGroup bossGroup = new NioEventLoopGroup(100) ;


        try {
            long t1 = System.currentTimeMillis() ;
            ServerBootstrap b = new ServerBootstrap().group(bossGroup);

            b.channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast("decoder", new HttpRequestDecoder(8192, 8192 * 2,
                                    8192 * 2));
                            ch.pipeline().addLast("encoder", new HttpResponseEncoder());

                            ch.pipeline().addLast(new TestServerHandler(TestServer.this));
                        }

                        @Override
                        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                            System.err.println("Error");
                            super.exceptionCaught(ctx,cause);
                        }


                    })
                    .option(ChannelOption.SO_BACKLOG, 100000)
                    .option(ChannelOption.SO_KEEPALIVE,false)
                    .option(ChannelOption.TCP_NODELAY,false)
                    .option(ChannelOption.SO_REUSEADDR,true)
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS,10000)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);

            ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);;

            scheduler.scheduleAtFixedRate(new Runnable() {
                @Override
                public void run()  {
                    System.err.println(nbSockets);
                    nbSockets = 0 ;
                }
            },1, 1,TimeUnit.SECONDS) ;


            // Bind and start to accept incoming connections.
            ChannelFuture f = b.bind(port).sync();

            f.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            System.err.println("Coucou");
        }
    }

    public static void main(String[] args) {
        TestServer testServer = new TestServer() ;
        testServer.init(8888);
    }
}

这是我的处理程序的源代码:

public class TestServerHandler extends ChannelInboundHandlerAdapter {
    private final TestServer testServer;

    public TestServerHandler(TestServer testServer) {
        this.testServer = testServer ;
    }


    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        try {
            process(ctx, msg);
        } catch (Throwable e) {
            e.printStackTrace();
        }


    }

    public void process(ChannelHandlerContext ctx, Object msg) throws Exception {
        ctx.channel().writeAndFlush(buildHttpResponse()).addListener(new GenericFutureListener>() {
            @Override
            public void operationComplete(Future future) throws Exception {
                ctx.channel().close() ;
                testServer.nbSockets ++ ;
            }
        }) ;
    }

    public DefaultFullHttpResponse buildHttpResponse() {

        String body = "hello world" ;
        byte[] bytes = body.getBytes(Charset.forName("UTF-8"));
        ByteBuf byteContent = Unpooled.copiedBuffer(bytes);
        HttpResponseStatus httpResponseStatus =HttpResponseStatus.OK;

        DefaultFullHttpResponse httpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
                httpResponseStatus, byteContent);


        return httpResponse;
    }

}

Stephane Lan.. 5

你已经禁用了keep-alive并且正在关闭每个请求的连接,所以我怀疑你花了大部分时间来打开和关闭HTTP连接.

因为其他基准测试的结果显示> 20 000 req/s或更多

您指的是哪些其他基准?很有可能它们都是池连接,并且使用HTTP流水线,因此与您的使用方式截然不同.

回到原来的问题(如何优化Netty),你可以做两件事:

微优化分配:使用池化的ByteBuffers,甚至更好地计算它们一次

切换到本机epoll传输(仅限Linux)

但是所有这些改进与连接处理相比可能不会太多.



1> Stephane Lan..:

你已经禁用了keep-alive并且正在关闭每个请求的连接,所以我怀疑你花了大部分时间来打开和关闭HTTP连接.

因为其他基准测试的结果显示> 20 000 req/s或更多

您指的是哪些其他基准?很有可能它们都是池连接,并且使用HTTP流水线,因此与您的使用方式截然不同.

回到原来的问题(如何优化Netty),你可以做两件事:

微优化分配:使用池化的ByteBuffers,甚至更好地计算它们一次

切换到本机epoll传输(仅限Linux)

但是所有这些改进与连接处理相比可能不会太多.

推荐阅读
贾志军
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有