2017-01-17 5 views
4

Я использую netty для загрузки больших файлов с сервера. При выполнении теста производительности с использованием jmeter я обнаружил, что мой сервер обеспечивает очень высокую пропускную способность до 150 одновременных пользователей, но как только количество одновременных пользователей увеличивается, он начинает снижаться и становится почти половиной из 500 одновременных пользователей.Медленная производительность нетто

NettyServer -

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(); 
    } 

FileServerInitializer -

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()); 
} 

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); 

Может кто-нибудь сказать мне, почему это происходит?

+1

Чем больше одновременных запросов сервер придется обрабатывать больше управления будет необходимо (бухгалтерский учет, контекст переключатели и т. д.), которые будут потреблять ваши ресурсы. Кроме того, вы, в конце концов, попадете в кепку ресурсов, например. CPU, память, полоса пропускания и т. Д., Что будет ограничивать общее время, а также уменьшать пропускную способность/пользователь. – Thomas

+1

@Thomas: Я сделал профилирование с использованием jmx/visualVM. Максимальная используемая память составляет 1,5 ГБ из 4 ГБ, максимальный КПК - 20%. О пропускной способности, я загружаю содержимое через LAN на 10gig трубе. –

+0

Возможно, все еще может быть некоторый дроссель на количество разрешенных одновременных запросов, и, следовательно, сервер будет приостанавливать любые избыточные запросы до тех пор, пока слот не будет освобожден. Также обратите внимание, что использование памяти и процессора не являются единственными ресурсами, которые могут ограничить ваше приложение. Это может быть диск io, количество дескрипторов файлов, количество потоков и т. Д., Или ваше приложение/vm по какой-то причине не использует весь cpus. Возможно, вам захочется профилировать ваше приложение и посмотреть, где он начинает замедляться, т. Е. Измерять, как часто выполняются части вашего кода и как эти части работают. – Thomas

ответ

2

Также вы можете попробовать:

  1. изменения подсвойств на стороне сети, например (получить собственные правильные значения)

    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); 
    
  2. адаптировать количество потоков как на BOSS и WORKER (по умолчанию 2N + 1, где N - это номер ядра для Boss, если я возвращаюсь правильно)

    Me Я обычно устанавливаю 2N + 1 для Boss и 10N + 1 для Работника (рассмотрите работу как асинхронный рабочий, что означает, что это не реальный предел для одновременного клиента, а только для «реальных» одновременных клиентов, что означает, что они действительно что-то делают). Будьте осторожны с Linux, чтобы соответственно увеличить лимит дескриптора файла.

  3. более точно указать ваш рабочий уровень резьбы

И посмотреть другие советы тоже конечно

Смежные вопросы