Netty рабочие потоки и пропускная способность - PullRequest
0 голосов
/ 09 мая 2018

Я создал netty-сервер с несколькими рабочими потоками, чтобы проверить, как увеличение количества потоков влияет на пропускную способность. Это код, который я использовал. Это слегка измененная версия Сервер записи и эха , который можно найти на веб-сайте Netty.

EchoServerCompute

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class EchoServerCompute {

    private int port;

    public EchoServerCompute(int port) {
        this.port = port;
    }

    public void run(int threadCount) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup(threadCount);
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
             .channel(NioServerSocketChannel.class)
             .childHandler(new ChannelInitializer<SocketChannel>() {
                 @Override
                 public void initChannel(SocketChannel ch) throws Exception {
                     ch.pipeline().addLast(new EchoServerComputeHandler());
                 }
             })
             .option(ChannelOption.SO_BACKLOG, 128)          
             .childOption(ChannelOption.SO_KEEPALIVE, true); 

            ChannelFuture f = b.bind(port).sync(); 

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

    public static void main(String[] args) throws Exception {
        int port = 8080;
        new EchoServerCompute(port).run(Integer.parseInt(args[0]));
    }
}

EchoServerComputeHandler

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.lang.Math;
import java.math.BigInteger;


public class EchoServerComputeHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) { 
        BigInteger result = BigInteger.ONE;
        for (int i=0; i<2000; i++)
            result = result.multiply(BigInteger.valueOf(i));
        ctx.write(msg);
        ctx.flush();
    }

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

Я запустил этот сервер с 5 рабочими потоками, а затем с 50 рабочими потоками и использовал JMeter с 1000 пользователями для его тестирования. Но пропускная способность, которую я получил в обоих случаях, была почти одинаковой.

Я ожидал увидеть увеличение пропускной способности при использовании большего количества рабочих потоков. Так может кто-нибудь сказать мне, если я здесь что-то не так делаю?

EDIT
В тестовой среде, где я работаю, есть 2 узла, обозначенные как Сервер и Клиент. На узле сервера выполняется программа netty, а на узле клиента - JMeter. Сервер имеет процессор Intel Xeon 5160 и 16 ГБ оперативной памяти. Клиент имеет процессор Intel Xeon E5506 и 8 ГБ оперативной памяти. Связь между ними составляет 1 Гбит / с.

Ответы [ 4 ]

0 голосов
/ 22 июня 2018

Netty разработан для поддержки неблокирующего ввода / вывода, что означает, что потоки не заблокированы. Переключение с одного потока на другой требует затрат, поэтому фиксированное количество потоков более эффективно. Это число обычно number_of_core × 2. Executor - это правильная абстракция для распределения задач между доступными потоками.

Просто подумайте, что как только каждое ядро ​​заработает на полную мощность, создание большего количества потоков не поможет. Увеличение размера пула потоков выше количества доступных физических потоков помогает только в случае блокирования ввода-вывода для обработки большего количества одновременных соединений.

Если ваши задачи не занимают слишком много времени, вы можете запустить их в том же пуле потоков, что и EventLoopGroup. Не пытайтесь регулировать количество потоков. Вместо этого отрегулируйте, как общее количество потоков распределяется между операциями ввода-вывода и задачами. Вы можете использовать два отдельных Executors (EventLoopGroup - один) или вы можете настроить значение EventLoopGroup#setIoRatio.

0 голосов
/ 09 мая 2018

Мои мысли:

  1. Удалить цикл, который выполняет умножение, и повторно протестировать
  2. Проверьте настройки JMeter. Не могли бы вы опубликовать свой поток конфигурации?
  3. Что такое текущие запросы в секунду / пропускная способность? А какова конфигурация вашей системы? Возможно, вы достигли ограничения вашей системы.
0 голосов
/ 09 мая 2018

Вы столкнулись с несколькими проблемами здесь:

Слишком умная Java

for (int i=0; i<2000; i++)
        result = result.multiply(BigInteger.valueOf(i));

JIT обнаружит это как мертвый код и просто полностью удалит его. Это означает, что ваш код будет завершен за доли миллисекунды. Чтобы исправить это, добавьте result к ответу, чтобы его нельзя было удалить.

Ваше оборудование ограничено

Больше рабочих потоков не обязательно означает большую пропускную способность, поскольку ваша машина действительно должна быть в состоянии справиться с рабочей нагрузкой. Если вы также запустите JMeter на той же машине, вы не увидите никакого увеличения пропускной способности даже при размере threads >= amount_of_cpus / 2. Имейте в виду, что если вы используете ЦП Intel, в нем есть гипер-ядра, которые регистрируются как «настоящие» ЦП. , но не буду делать никакой работы. Поэтому, если вы запускаете это на четырехъядерном процессоре Intel, не ожидайте увеличения пропускной способности после 2-го рабочего потока.

Поток занимает время

На самом деле требуется время для управления потоками и переключения между ними. Так что после определенного количества потоков в системе ваша пропускная способность заметно снизится. Ваш шаг от 5 до 50 - это слишком много, чтобы обнаружить это, попробуйте продвинуться шагами в 2 потока.

Резьба хаотична

Порядок выполнения с потоками не определен. Поэтому, если вы запустите достаточно потоков, они начнут украсть время выполнения друг у друга. Некоторые могут завершиться почти мгновенно, в то время как другие будут поставлены в очередь в течение нескольких секунд. На 50 потоках вы увидите намного больше времени для завершения просто потому, что так много потоков постоянно находятся в режиме ожидания. Вы можете убедиться в этом, сравнив минимальное и максимальное время выполнения, которое должно начать расходиться с ростом числа потоков.

0 голосов
/ 09 мая 2018

Из-за большинства http-серверов есть два ограничения рабочего потока.

Один - это максимальное количество рабочих потоков для «конечной точки». Другой - это максимальное количество рабочих потоков для сервера.

Конечная точка основана на ip adderss (или сеансе), максимальное число потоков по умолчанию для одной конечной точки равно 5. Так что, хотя вы создали 1000 пользователей для тестирования, но ваши 1000 пользователей принадлежат одной конечной точке, поэтому максимальная пропускная способность всегда равна 5.

Это ограничение нацелено на слишком большую нагрузку на один сервер запросов конечной точки, это не приведет к тому, что процесс обработки других конечных точек будет трудоемким, это будет серьезно и опасно.

...