Как использовать ChannelTrafficShapingHandler в Netty 4+?

Мне нужно передать клиенту большой файл, но я хочу ограничить скорость (например, 100 Кбит/с), как использовать ChannelTrafficShapingHandler?

ServerBootstrap b = new ServerBootstrap();
              b.group(bossGroup, workerGroup)
               .channel(NioServerSocketChannel.class)
               .option(ChannelOption.SO_BACKLOG, 100)
               .handler(new LoggingHandler(LogLevel.INFO))
               .childHandler(new ChannelInitializer<SocketChannel>() {
                   @Override
                   public void initChannel(SocketChannel ch) throws Exception {
                       ChannelPipeline p = ch.pipeline();

                       p.addLast(
                               new StringEncoder(CharsetUtil.UTF_8),
                               new LineBasedFrameDecoder(8192),
                               new StringDecoder(CharsetUtil.UTF_8),
                               new ChannelTrafficShapingHandler(1,1,10L),
                               new ChunkedWriteHandler(),
                               new FileServerHandler()
                               );
                   }
               });

Эта демонстрация не работает, почему?


person 高鸿武    schedule 17.12.2015    source источник


Ответы (1)


Вы управляли возможностью записи канала в FileServerHandler?

Как указано в Netty API для ChannelTrafficShapingHandler.

В вашем обработчике вы должны рассмотреть возможность использования channel.isWritable() и channelWritabilityChanged(ctx) для обработки возможности записи или через future.addListener(new GenericFutureListener()) для будущего, возвращаемого ctx.write().

Вы также должны рассмотреть вопрос о том, чтобы размер объекта в операциях чтения или записи был относительно адаптирован к требуемой пропускной способности: например, наличие объектов размером 10 МБ для 10 КБ/с приведет к эффекту взрыва, в то время как объекты размером 100 КБ для 1 МБ/с должны быть плавными. обрабатывается этим обработчиком TrafficShaping.

И инициализация:

  • Первый пункт — Ограничение записи в Б/с (здесь 1 настоятельно не рекомендуется, что-то близкое к 1024 минимально для 1 КБ/с)
  • второй пункт — Ограничение на чтение в B/S (здесь 1 настоятельно не рекомендуется, что-то близкое к 1024 минимально для 1 КБ/с или 0 для без ограничений)
  • Первый пункт — проверка интервала в мс (Здесь 1L означает каждую мс, что настоятельно не рекомендуется, что-то близкое к 1000 минимально для каждой 1 с)

Вы можете увидеть пример (на примере Discard) здесь, в частности:

person Frederic Brégier    schedule 17.12.2015
comment
Не могли бы вы объяснить, что делает checkInterval? Я этого не понимаю. - person Alexander; 12.02.2019
comment
@Alexander, как говорится в документе: checkInterval - задержка между двумя вычислениями производительности для каналов или 0, если статистика не рассчитывается. Это означает, что пропускная способность должна время от времени каким-то образом вычисляться. Пропускная способность известна не сразу, а из недавнего прошлого, где recent — как вам угодно. 1 мс слишком мало, чтобы получить правильное вычисление (в среднем), 1 с обычно является хорошим выбором. - person Frederic Brégier; 13.02.2019
comment
Означает ли это, что дросселирование применяется с помощью прямоугольной волны, чередующейся между максимальной скоростью и нулевой скоростью, с рабочим циклом, который усредняется до установленного вами предела дросселя? - person Alexander; 13.02.2019
comment
Это не от 0 до полной скорости. Да, вычисление пропускной способности проверяет правильность того, что отправляется (байты по времени). Но точность зависит от этого интервала. Чем меньше, тем лучше, но слишком маленький подразумевает слишком много обратных вызовов. Действительно, после записи в провод нет реального способа предотвратить быструю передачу пакета. Но можно предотвратить отправку пакета время от времени. Таким образом, пропускная способность больше связана с ограничением пакетов, где осуществляется дополнительный контроль, статистика с использованием этого интервала. Надеюсь понятно... ;-) - person Frederic Brégier; 15.02.2019
comment
Понятно! Спасибо за объяснение! - person Alexander; 15.02.2019
comment
Не могли бы вы объяснить параметр maxTime? Означает ли это, что пакеты, которые были дросселированы, будут задержаны не более чем на maxTime, а затем будут освобождены? - person Alexander; 06.03.2019
comment
Да, точно. maxTime указывает ограничение по времени, в течение которого пакет будет выпущен независимо от пропускной способности. Это делается для того, чтобы не было тупиковой блокировки (я знаю, что сравнение некорректно, но все же нужно объяснить эту проблему, которую она пытается предотвратить). - person Frederic Brégier; 07.03.2019
comment
То есть это означает, что это может ограничивать только всплески пропускной способности, но его нельзя использовать для реализации устойчивого дросселя? - person Alexander; 08.03.2019
comment
Дросселирование поддерживается во времени, используя размеры пакетов при получении или отправке. Конечно, отправка более точна, так как Netty может реализовать собственную буферизацию способа отправки пакетов. Напротив, получение больше связано со статусом принятия соединения и входящим буфером Netty, конечно. Эти ограничения предназначены для максимально точного дросселирования. Отправка почти идеальна, за исключением ограничения maxTime, которое предотвращает побочные эффекты, такие как потеря KeepAlive. - person Frederic Brégier; 08.03.2019
comment
У меня все это есть, кроме последнего предложения: Отправка почти идеальна, за исключением ограничения maxTime, которое предотвращает побочные эффекты, такие как потеря KeepAlive. Не могли бы вы уточнить это? - person Alexander; 08.03.2019
comment
Хорошо, я попытаюсь уточнить. Допустим, вы указали очень низкий порог (скажем, 1 Б/с) и хотите отправить 1 МБ. Затем это должно занять 1 миллион секунд в соответствии с ограничением пропускной способности. Но в большинстве случаев, что происходит в этом крайнем случае, система KeepAlive пытается предотвратить (с точки зрения получателя) отсутствие получения данных. Но так как вы ограничиваете отправку (throttle), ответ KeepAlive тоже будет приходить с большим опозданием, поэтому клиент отключит соединение. Поэтому, чтобы предотвратить это, обычно помещают maxTime в ограничение KeepAlive (например, 30 секунд), чтобы принудительно отправить некоторые из них. - person Frederic Brégier; 09.03.2019
comment
Если нет, то теряется ответ KeepAlive, а значит и передача тоже (как устаревшее соединение). Таким образом, использование этого параметра близко к лимиту KeepAlive поможет соединению оставаться открытым и функциональным, за счет принятия дополнительной отправки в период maxTime, но только в случае необходимости. Если необходимо, это означает, что если какие-то данные были отправлены в течение периода, эталонное время сбрасывается, поэтому 30 секунд (или около того) снова отсчитываются в обратном порядке. Таким образом, этот параметр полезен только в очень ограниченной ситуации. - person Frederic Brégier; 09.03.2019