Я загружаю некоторые данные, используя HTTP-библиотеку, в какой-то веб-сервис, и мне нужно ограничить количество загружаемых данных в секунду.Используется лимитер Guava RateLimiter , в значительной степени следуя второму примеру, ограничивающему некоторый поток данных.Два отличия для меня: я предоставляю немного InputStream
потребителю и использую aquire
в методе read , предоставляя только один байт за раз.Никаких пакетов разного размера или такого, которые, по моему мнению, должны облегчить задачу.Кроме того, мои разрешения в секунду больше, чем в примере.
Вещи, казалось, работали довольно хорошо для низких чисел, но не для более высоких, и есть ровно одно число, при котором вещи больше не работают.Я ограничиваю в терминах КиБ / с, и все, до 1 * 1024 * 976
включительно, работает, но с 977
вещи начинают терпеть неудачу, и ограничение, кажется, больше не применяется.Это легко увидеть, используя какой-то сетевой монитор: первая конфигурация ограничивает загрузку ~ 7-8 Мбит / с, а последняя увеличивает до 60 или более, в зависимости от того, как используется исходящий интерфейс, и так далее.Насколько я понимаю, увеличение загрузки должно быть намного меньше, всего 1 КиБ / с и поэтому вообще не заметно.
Я могу воспроизвести проблему, используя следующий код:
import com.google.common.util.concurrent.RateLimiter;
public class Test
{
public static void main(String[] args)
{
RateLimiter rateLimiter = RateLimiter.create(1 * 1024 * 976);
RateLimiter msgLimiter = RateLimiter.create(1);
long aquired = 0L;
while (true)
{
rateLimiter.acquire();
++aquired;
if (msgLimiter.tryAcquire())
{
System.out.println(
String.format( "Aquired: %d MBit/s",
(aquired * 8) / (1024 * 1024)));
aquired = 0;
}
}
}
}
Результаты с 976
:
Aquired: 0 MBit/s
Aquired: 7 MBit/s
Aquired: 7 MBit/s
Aquired: 7 MBit/s
Aquired: 7 MBit/s
Результаты с 977
:
Aquired: 0 MBit/s
Aquired: 77 MBit/s
Aquired: 85 MBit/s
Aquired: 82 MBit/s
Aquired: 83 MBit/s
У вас есть идеи, почему это происходит?Спасибо!
Я уже читал о "недостатках" RateLimiter в отношении всплесков и тому подобного, но не знаю, объясняет ли это и как это объясняет мою проблему.
Проблема не возникает при использовании TimedSemaphore :
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.concurrent.TimedSemaphore;
import com.google.common.util.concurrent.RateLimiter;
public class Test
{
public static void main(String[] args) throws InterruptedException
{
int rateLimit = 1 * 1024 * 2000;
//RateLimiter rateLimiter = RateLimiter.create(rateLimit);
TimedSemaphore rateLimiter = new TimedSemaphore(1, TimeUnit.SECONDS, rateLimit);
RateLimiter msgLimiter = RateLimiter.create(1);
long aquired = 0L;
while (true)
{
rateLimiter.acquire();
++aquired;
if (msgLimiter.tryAcquire())
{
System.out.println(
String.format( "Aquired: %d MBit/s",
(aquired * 8) / (1024 * 1024)));
aquired = 0;
}
}
}
}
Результаты с 976
такие же, как и раньше, поэтому более высокие значения представляют больший интерес:
Aquired: 0 MBit/s
Aquired: 15 MBit/s
Aquired: 15 MBit/s
Aquired: 15 MBit/s
Aquired: 15 MBit/s