Java 慢网性能
我正在使用netty从服务器下载大文件。在使用jmeter运行性能测试时,我发现我的服务器提供了非常高的吞吐量,直到150个并发用户,但一旦并发用户数量增加,它就开始下降,几乎是500个并发用户的一半 NettyServer-Java 慢网性能,java,netty,Java,Netty,我正在使用netty从服务器下载大文件。在使用jmeter运行性能测试时,我发现我的服务器提供了非常高的吞吐量,直到150个并发用户,但一旦并发用户数量增加,它就开始下降,几乎是500个并发用户的一半 NettyServer- ServerBootstrap b = new ServerBootstrap(); EpollEventLoopGroup bossGroup = new EpollEventLoopGroup(); EpollEventLoopGroup worker
ServerBootstrap b = new ServerBootstrap();
EpollEventLoopGroup bossGroup = new EpollEventLoopGroup();
EpollEventLoopGroup workerGroup = new EpollEventLoopGroup();
try {
b.group(bossGroup, workerGroup).channel(EpollServerSocketChannel.class).handler(new LoggingHandler(LogLevel.DEBUG)).childHandler(new FileServerInitializer());
Channel ch = b.bind(port).sync().channel();
ch.closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
FileServerHandler.threadPool.shutdownNow();
}
文件服务器初始值设定项-
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("decoder", new HttpRequestDecoder());
pipeline.addLast("aggregator", new HttpObjectAggregator(65536));
pipeline.addLast("encoder", new HttpResponseEncoder());
pipeline.addLast("chunkedWriter", new ChunkedWriteHandler());
pipeline.addLast("handler", (ChannelHandler) new FileServerHandler());
}
文件服务器处理程序-
RandomAccessFile raf;
try {
raf = new RandomAccessFile(file, "r");
} catch (FileNotFoundException ignore) {
sendError(ctx, HttpResponseStatus.NOT_FOUND);
return;
}
response = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.OK);
response.headers().set(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + fileNameType);
response.headers().set(HttpHeaders.CONTENT_LENGTH, String.valueOf(size));
ctx.write(response);
ChannelFuture sendFileFuture;
ChannelFuture lastContentFuture;
sendFileFuture = ctx.writeAndFlush(new HttpChunkedInput(new ChunkedFile(raf, 0, size, 8192)),ctx.newProgressivePromise());
lastContentFuture = sendFileFuture;
sendFileFuture.addListener(new ChannelProgressiveFutureListener() {
public void operationProgressed(ChannelProgressiveFuture future, long progress, long total) {
if (total < 0) {
System.out.println(future.channel() + " Transfer progress: " + progress);
}else {
System.out.println(future.channel() + " Transfer progress: " + progress + " / " + total);
}
}
public void operationComplete(ChannelProgressiveFuture future) {
System.out.println(future.channel() + " Transfer complete.");
}
});
lastContentFuture.addListener(ChannelFutureListener.CLOSE);
随机存取文件raf;
试一试{
raf=新随机访问文件(文件“r”);
}捕获(FileNotFoundException忽略){
sendError(未找到ctx、HttpResponseStatus.NOT_);
返回;
}
response=newdefaulthttpresponse(HTTP_1_1,HttpResponseStatus.OK);
response.headers().set(HttpHeaders.CONTENT_处置,“附件;文件名=“+fileNameType”);
response.headers().set(HttpHeaders.CONTENT_LENGTH,String.valueOf(size));
写(应答);
渠道未来发送文件未来;
渠道未来;内容未来;
sendFileFuture=ctx.writeAndFlush(新的HttpChunkedInput(新的ChunkedFile(raf,0,size,8192)),ctx.newProgressivePromise());
lastContentFuture=sendFileFuture;
sendFileFuture.addListener(新通道ProgressiveFutureListener(){
公共无效运营进展(渠道进展未来、长期进展、长期总计){
如果(总数<0){
System.out.println(future.channel()+“传输进度:”+进度);
}否则{
System.out.println(future.channel()+“传输进度:”+进度+“/”+总计);
}
}
公共无效操作完成(渠道进展未来){
System.out.println(future.channel()+“传输完成”);
}
});
lastContentFuture.addListener(ChannelFutureListener.CLOSE);
有人能告诉我为什么会发生这种情况吗?您也可以尝试:
当然,也可以参考其他建议服务器必须处理的并发请求越多,需要的管理(簿记、上下文切换等)就越多,这将消耗您的资源。此外,您最终将达到资源上限,例如CPU、内存、带宽等,这将限制整个进程,并降低吞吐量/用户。@Thomas:我已经使用jmx/visualVM完成了评测。使用的最大内存为4GB中的1.5GB,最大CPU为20%。关于带宽,我正在通过10gig管道上的LAN下载内容。对于允许的并发请求数量,可能仍有一些限制,因此服务器将暂停任何多余的请求,直到释放插槽为止。还要注意,内存和cpu使用率并不是限制应用程序的唯一资源。可能是磁盘io、文件句柄数、线程数等,或者您的应用程序/vm由于某种原因没有使用所有CPU。您可能希望分析应用程序并查看它从何处开始变慢,即测量代码部分的执行频率以及这些部分的运行方式。尝试使用发送文件的方法发送文件以减少内存瓶颈:@Ferrybig:如前所述,没有内存瓶颈。我们有8GB的虚拟机,其中只有700MB-1GB得到利用。我也试过,但结果还是一样的。
bootstrap.channel(NioServerSocketChannel.class);
bootstrap.group(groupBoss, groupWorker);
bootstrap.option(ChannelOption.TCP_NODELAY, true);
bootstrap.option(ChannelOption.SO_REUSEADDR, true);
bootstrap.option(ChannelOption.SO_LINGER, 0);
bootstrap.childOption(ChannelOption.TCP_NODELAY, true);
bootstrap.childOption(ChannelOption.SO_REUSEADDR, true);
bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
bootstrap.childOption(ChannelOption.SO_LINGER, 0);
bootstrap.childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeout);
bootstrap.childOption(ChannelOption.SO_RCVBUF, 1048576);
bootstrap.childOption(ChannelOption.SO_SNDBUF, 1048576);
bootstrap.childOption(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 10*65536);
bootstrap.childOption(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 2*65536);
bootstrap.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);