Netty应用优化
Netty application optimization
我正在编写一个基于 Netty 的本地 HTTP 服务器。当我进行压力测试时,我被限制在 400 requests/second.
为了优化我的服务器,我编写了一个基于 Netty 的简单服务器,它只向客户端发送 "Hello World",并且我使用 Gatling 2 启动了压力测试,并且使用这个服务器,我'我们得到了相同的结果(限制为 400 req/s)。
我使用 Yourkit 进行分析,没有额外的 GC activity,我的 open/closed sockets 限制为 480 sockets/s.
我使用 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<SocketChannel>() {
@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<Future<? super Void>>() {
@Override
public void operationComplete(Future<? super Void> 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;
}
}
您已禁用保持活动状态并在每次请求时关闭连接,因此我怀疑您大部分时间都在打开和关闭 HTTP 连接上。
because the result of other benchmark tests show >20 000 req/s, or more
您指的是其他哪些基准?他们很有可能都在使用 HTTP 流水线和池化连接,因此与您的用法截然不同。
回到你最初的问题(如何优化 Netty),你可以做两种事情:
- 微优化分配:使用池化的 ByteBuffer,或者甚至更好地只计算一次
- 切换到 native epoll transport(仅限 Linux)
但与连接处理相比,所有这些改进可能都不算多。
我正在编写一个基于 Netty 的本地 HTTP 服务器。当我进行压力测试时,我被限制在 400 requests/second.
为了优化我的服务器,我编写了一个基于 Netty 的简单服务器,它只向客户端发送 "Hello World",并且我使用 Gatling 2 启动了压力测试,并且使用这个服务器,我'我们得到了相同的结果(限制为 400 req/s)。
我使用 Yourkit 进行分析,没有额外的 GC activity,我的 open/closed sockets 限制为 480 sockets/s.
我使用 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<SocketChannel>() {
@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<Future<? super Void>>() {
@Override
public void operationComplete(Future<? super Void> 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;
}
}
您已禁用保持活动状态并在每次请求时关闭连接,因此我怀疑您大部分时间都在打开和关闭 HTTP 连接上。
because the result of other benchmark tests show >20 000 req/s, or more
您指的是其他哪些基准?他们很有可能都在使用 HTTP 流水线和池化连接,因此与您的用法截然不同。
回到你最初的问题(如何优化 Netty),你可以做两种事情:
- 微优化分配:使用池化的 ByteBuffer,或者甚至更好地只计算一次
- 切换到 native epoll transport(仅限 Linux)
但与连接处理相比,所有这些改进可能都不算多。