简体   繁体   English

Netty作为高性能Http服务器处理大约2-3百万个请求/秒

[英]Netty as High Performant Http Server to Handle ~2-3 Million Requests/Sec

We are trying to Solve the Problem of Handling Huge Volume of Http POST Requests, and while using Netty Server, I was able to handle only ~50K requests/sec which is too low. 我们正在尝试解决处理大量Http POST请求的问题,并且在使用Netty Server时,我只能处理~50K requests/sec ,这太低了。

My question is how to tune this Server to ensure to handle > 1.5 million requests/second ? 我的问题是如何调整此服务器以确保处理> 1.5 million requests/second

Netty4 Server Netty4服务器

// Configure the server.
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
        ServerBootstrap b = new ServerBootstrap();
        b.option(ChannelOption.SO_BACKLOG, 1024);

        b.group(bossGroup, workerGroup)
         .channel(NioServerSocketChannel.class)
         .handler(new LoggingHandler(LogLevel.INFO))
         .childHandler(new HttpServerInitializer(sslCtx));

        Channel ch = b.bind(PORT).sync().channel();

        System.err.println("Open your web browser and navigate to " +
                (SSL? "https" : "http") + "://127.0.0.1:" + PORT + '/');

        ch.closeFuture().sync();
    } finally {
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
    }

Initializer 初始化

    public class HttpServerInitializer extends ChannelInitializer<SocketChannel> {

    private final SslContext sslCtx;

    public HttpServerInitializer(SslContext sslCtx) {
        this.sslCtx = sslCtx;
    }

    @Override
    public void initChannel(SocketChannel ch) {
        ChannelPipeline p = ch.pipeline();
        if (sslCtx != null) {
            p.addLast(sslCtx.newHandler(ch.alloc()));
        }
        p.addLast(new HttpServerCodec());
        p.addLast("aggregator", new HttpObjectAggregator(Integer.MAX_VALUE));
        p.addLast(new HttpServerHandler());
    }
}

Handler 处理器

public class HttpServerHandler extends ChannelInboundHandlerAdapter {
private static final String CONTENT = "SUCCESS";

@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
    ctx.flush();
}

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
    if (msg instanceof HttpRequest) {
        HttpRequest req = (HttpRequest) msg;
        final FullHttpRequest fReq = (FullHttpRequest) req;
        Charset utf8 = CharsetUtil.UTF_8;
        final ByteBuf buf = fReq.content();
        String in = buf.toString( utf8 );
        System.out.println(" In ==> "+in);
        buf.release();
        if (HttpHeaders.is100ContinueExpected(req)) {
            ctx.write(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE));
        }
        in = null;
        if (HttpHeaders.is100ContinueExpected(req)) {
            ctx.write(new DefaultFullHttpResponse(HTTP_1_1, CONTINUE));
        }
        boolean keepAlive = HttpHeaders.isKeepAlive(req);
        FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(CONTENT.getBytes()));
        response.headers().set(CONTENT_TYPE, "text/plain");
        response.headers().set(CONTENT_LENGTH, response.content().readableBytes());

        if (!keepAlive) {
            ctx.write(response).addListener(ChannelFutureListener.CLOSE);
        } else {
            response.headers().set(CONNECTION, Values.KEEP_ALIVE);
            ctx.write(response);
        }
    }
}

@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
{
        cause.printStackTrace();
        ctx.close();
    }

}

Your question is very generic. 你的问题非常通用。 However, I'll try to give you an answer regarding the netty optimizations and your code improvements. 但是,我将尝试为您提供有关netty优化和代码改进的答案。

Your code issues: 您的代码问题:

  1. System.out.println(" In ==> "+in); - you shouldn't use this in high load cocurrent handler. - 你不应该在高负载并流处理程序中使用它。 Why? 为什么? Because code inside println method is synchronized and thus gives penalties to your performance; 因为println方法中的代码是同步的,因此会对您的性能造成惩罚;
  2. You do 2 class casts. 你做2级演员表。 To HttpRequest and to FullHttpRequest . HttpRequestFullHttpRequest You may use just last one; 你可以使用最后一个;

Netty specific issues in your code: 代码中的Netty特定问题:

  1. You need to add epoll transport (in case your server is Linux like). 你需要添加epoll传输(如果你的服务器像Linux一样)。 It will give + ~30% out of box; 开箱即可达到+ ~30%; How to . 怎么样
  2. You need to add native OpenSSL bindings. 您需要添加本机OpenSSL绑定。 It will give + ~20%. 它会给出+ ~20%。 How to . 怎么样
  3. EventLoopGroup bossGroup = new NioEventLoopGroup(); - you need to correctly setup sizes of bossGroup and workerGroup groups. - 您需要正确设置bossGroupworkerGroup组的大小。 Depending on your test scenarios. 取决于您的测试方案。 You didn't provide any info regarding your test cases, so I can't give you advice here; 你没有提供有关你的测试用例的任何信息,所以我不能在这里给你建议;
  4. new HttpObjectAggregator(Integer.MAX_VALUE) - you actually don't need this handler in your code. new HttpObjectAggregator(Integer.MAX_VALUE) - 实际上你的代码中不需要这个处理程序。 So for better performance, you may remove it. 因此,为了获得更好的性能,您可以删除它。
  5. new HttpServerHandler() - you don't need to create this handler for every channel. new HttpServerHandler() - 您不需要为每个通道创建此处理程序。 As it doesn't hold any state it may be shared across all pipelines. 由于它没有任何状态,因此可以在所有管道中共享。 Search for @Sharable in netty. @Sharable中搜索@Sharable
  6. new LoggingHandler(LogLevel.INFO) - you don't need this handler for high load tests as it logs a lot. new LoggingHandler(LogLevel.INFO) - 你不需要这个处理程序来进行高负载测试,因为它记录了很多。 Make your own logging when necessary; 必要时进行自己的记录;
  7. buf.toString( utf8 ) - this is very wrong. buf.toString( utf8 ) - 这是非常错误的。 You convert income bytes to string. 您将收入字节转换为字符串。 But this doesn't make any sense as all data is already decoded in netty HttpServerCodec . 但这没有任何意义,因为所有数据都已在netty HttpServerCodec解码。 So you do double work here; 所以你在这里做双重工作;
  8. Unpooled.wrappedBuffer(CONTENT.getBytes()) - you wrap constant message on every request. Unpooled.wrappedBuffer(CONTENT.getBytes()) - 在每个请求上包装常量消息。 And thus - do unnecessary work on every request. 因此 - 对每个请求都做不必要的工作。 You may create ByteBuf only once and do retain() , duplicate() depending on how you'll do this; 您可以只创建一次ByteBuf并执行retain()duplicate()具体取决于您将如何执行此操作;
  9. ctx.write(response) - you may consider using ctx.write(response, ctx.voidPromise()) in order to allocate less; ctx.write(response) - 您可以考虑使用ctx.write(response, ctx.voidPromise())来分配更少的内容;

This is not all. 这还不是全部。 However, fixing above issues would be a good start. 但是,解决上述问题将是一个良好的开端。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM