我正在使用一些HTTP库将某些数据上传到某些Web服务,并且需要限制每秒上传的数据量。使用的限制器为Guava RateLimiter,在第二个示例中限制了一些数据流之后。对我来说有两个区别:我正在向消费者提供一些InputStream
,并且在read方法中使用aquire
,一次只能提供一个字节。据我所知,没有大小不同的数据包会使事情变得更容易。另外,我的每秒许可数比示例要大。
对于较低的数字,事情似乎工作得很好,但是对于较高的数字,事情就不行了,而且只有一个数字,事情开始不再起作用。我在KiB / s方面进行了限制,直到1 * 1024 * 976
为止,包括977
都可以使用,但是一切开始失败,并且限制似乎不再适用。使用某些网络监视器可以很容易地看到这一点,第一个配置将上传速度限制为〜7-8 MBit / s,而后者则提高了60或更高,具体取决于传出接口的使用方式等。据我了解,上传的增加应该小得多,仅为1 KiB / s,因此一点也不明显。
我可以使用以下代码重现该问题:
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
您知道为什么会这样吗?谢谢!
我已经读过有关Rate bursts等的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
答案 0 :(得分:1)
似乎Guava RateLimiter每秒最多只能处理1,000,000个获取呼叫。如果您尝试每秒进行1,000,001次获取呼叫,则对aquire
的呼叫将根本不会等待(aquire()
的返回值始终为0.0)->没有任何限制。
因此,以下情况可以按预期工作:
RateLimiter.create(1000000l);
//使用aquire()
/ aquire(1)
RateLimiter.create(100000000l);
//使用aquire(100)
或更高版本时将起作用。
假设从不逐字节接收典型的网络流量,但是在100-1000字节的块中,Guava RateLimiter的工作极限为每个字节100,000,000(〜762 MBit)至1,000,000,000(7.45 GBit / s)字节第二。
如果这些值足以满足您的项目需求,则可以坚持使用Guava RateLimiter。如果没有,我建议改用Apache TimedSemaphore。