@Test public void testEagerGrantingIfUnderused() throws Exception { int qps = 100; DynamicTokenBucket limiter = new DynamicTokenBucket(qps, 10, 100); Thread.sleep(100); // fill bucket // Grant 4 permits even though only 1 requested Assert.assertTrue(limiter.getPermits(1, 0, 100) > 4); }
public QPSPolicy(Config config) { Preconditions.checkArgument(config.hasPath(QPS), "QPS required."); this.qps = config.getLong(QPS); long fullRequestTimeoutMillis = config.hasPath(FULL_REQUEST_TIMEOUT_MILLIS) ? config.getLong(FULL_REQUEST_TIMEOUT_MILLIS) : DEFAULT_FULL_REQUEST_TIMEOUT; long maxBucketSizeMillis = config.hasPath(MAX_BUCKET_SIZE_MILLIS) ? config.getLong(MAX_BUCKET_SIZE_MILLIS) : DEFAULT_MAX_BUCKET_SIZE; this.tokenBucket = new DynamicTokenBucket(qps, fullRequestTimeoutMillis, maxBucketSizeMillis); }
@Override public PermitAllocation computePermitAllocation(PermitRequest request) { long permitsRequested = request.getPermits(); Long minPermits = request.getMinPermits(GetMode.NULL); if (minPermits == null) { minPermits = permitsRequested; } long permitsGranted = this.tokenBucket.getPermits(permitsRequested, minPermits, LimiterServerResource.TIMEOUT_MILLIS); PermitAllocation allocation = new PermitAllocation(); allocation.setPermits(permitsGranted); allocation.setExpiration(Long.MAX_VALUE); if (permitsGranted <= 0) { allocation.setMinRetryDelayMillis(LimiterServerResource.TIMEOUT_MILLIS); } return allocation; }
@Override public void run() { DescriptiveStatistics stats = limiter.getRateStatsSinceLastReport(); if (stats != null) { log.info(String.format("Requests rate stats: count: %d, min: %f, max: %f, mean: %f, std: %f, sum: %f", stats.getN(), stats.getMin(), stats.getMax(), stats.getMean(), stats.getStandardDeviation(), stats.getSum())); } stats = limiter.getUnusedPermitsSinceLastReport(); if (stats != null) { log.info(String.format("Unused permits rate stats: count: %d, min: %f, max: %f, mean: %f, std: %f, sum: %f", stats.getN(), stats.getMin(), stats.getMax(), stats.getMean(), stats.getStandardDeviation(), stats.getSum())); } if (this.policy instanceof QPSPolicy) { QPSPolicy qpsPolicy = (QPSPolicy) this.policy; DynamicTokenBucket dynamicTokenBucket = qpsPolicy.getTokenBucket(); TokenBucket tokenBucket = dynamicTokenBucket.getTokenBucket(); log.info("Stored tokens: " + tokenBucket.getStoredTokens()); } } }
public QPSPolicy(Config config) { Preconditions.checkArgument(config.hasPath(QPS), "QPS required."); this.qps = config.getLong(QPS); long fullRequestTimeoutMillis = config.hasPath(FULL_REQUEST_TIMEOUT_MILLIS) ? config.getLong(FULL_REQUEST_TIMEOUT_MILLIS) : DEFAULT_FULL_REQUEST_TIMEOUT; long maxBucketSizeMillis = config.hasPath(MAX_BUCKET_SIZE_MILLIS) ? config.getLong(MAX_BUCKET_SIZE_MILLIS) : DEFAULT_MAX_BUCKET_SIZE; this.tokenBucket = new DynamicTokenBucket(qps, fullRequestTimeoutMillis, maxBucketSizeMillis); }
@Override public PermitAllocation computePermitAllocation(PermitRequest request) { long permitsRequested = request.getPermits(); Long minPermits = request.getMinPermits(GetMode.NULL); if (minPermits == null) { minPermits = permitsRequested; } long permitsGranted = this.tokenBucket.getPermits(permitsRequested, minPermits, LimiterServerResource.TIMEOUT_MILLIS); PermitAllocation allocation = new PermitAllocation(); allocation.setPermits(permitsGranted); allocation.setExpiration(Long.MAX_VALUE); if (permitsGranted <= 0) { allocation.setMinRetryDelayMillis(LimiterServerResource.TIMEOUT_MILLIS); } return allocation; }
@Test public void test() throws Exception { int qps = 10; DynamicTokenBucket limiter = new DynamicTokenBucket(qps, 10, 0); // Requesting 10 seconds worth of permits with 1 second timeout fails Assert.assertEquals(limiter.getPermits(10 * qps, 10 * qps, 1000), 0); // Requesting 0.2 seconds worth of permits with 300 millis timeout succeeds long permits = qps / 5; Assert.assertEquals(limiter.getPermits(permits, permits, 300), permits); // Requesting 1 seconds worth of permits, with min of 0.1 seconds, and with 200 millis timeout will return at least // min permits permits = qps; Assert.assertTrue(limiter.getPermits(permits, qps / 10, 200) >= qps / 10); }