-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#110 add RateLimiterUtil for RateLimiter customization
- Loading branch information
1 parent
d4ef617
commit 9eacb86
Showing
2 changed files
with
101 additions
and
0 deletions.
There are no files selected for viewing
80 changes: 80 additions & 0 deletions
80
vjkit/src/main/java/com/vip/vjtools/vjkit/concurrent/RateLimiterUtil.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package com.vip.vjtools.vjkit.concurrent; | ||
|
||
import java.lang.reflect.Constructor; | ||
import java.lang.reflect.Field; | ||
import java.lang.reflect.Method; | ||
|
||
import com.google.common.util.concurrent.RateLimiter; | ||
|
||
public class RateLimiterUtil { | ||
|
||
/** | ||
* 一个用来定制RateLimiter的方法。默认装满token | ||
* | ||
* @param permitsPerSecond 每秒允许的请求书,可看成QPS | ||
* @param maxBurstSeconds 最大的突发缓冲时间。用来应对突发流量。Guava的实现默认是1s。permitsPerSecond * maxBurstSeconds的数量,就是闲置时预留的缓冲token数量 | ||
*/ | ||
public static RateLimiter create(double permitsPerSecond, double maxBurstSeconds) | ||
throws ReflectiveOperationException { | ||
return create(permitsPerSecond, maxBurstSeconds, true); | ||
} | ||
|
||
/** | ||
* 一个用来定制RateLimiter的方法。 | ||
* | ||
* @param permitsPerSecond 每秒允许的请求书,可看成QPS | ||
* @param maxBurstSeconds 最大的突发缓冲时间。用来应对突发流量。Guava的实现默认是1s。permitsPerSecond * maxBurstSeconds的数量,就是闲置时预留的缓冲token数量 | ||
* @param filledWithToken 是否需要创建时就保留有permitsPerSecond * maxBurstSeconds的token | ||
*/ | ||
public static RateLimiter create(double permitsPerSecond, double maxBurstSeconds, boolean filledWithToken) | ||
throws ReflectiveOperationException { | ||
Class<?> sleepingStopwatchClass = Class | ||
.forName("com.google.common.util.concurrent.RateLimiter$SleepingStopwatch"); | ||
Method createStopwatchMethod = sleepingStopwatchClass.getDeclaredMethod("createFromSystemTimer"); | ||
createStopwatchMethod.setAccessible(true); | ||
Object stopwatch = createStopwatchMethod.invoke(null); | ||
|
||
Class<?> burstyRateLimiterClass = Class | ||
.forName("com.google.common.util.concurrent.SmoothRateLimiter$SmoothBursty"); | ||
Constructor<?> burstyRateLimiterConstructor = burstyRateLimiterClass.getDeclaredConstructors()[0]; | ||
burstyRateLimiterConstructor.setAccessible(true); | ||
|
||
// set maxBurstSeconds | ||
RateLimiter rateLimiter = (RateLimiter) burstyRateLimiterConstructor.newInstance(stopwatch, maxBurstSeconds); | ||
rateLimiter.setRate(permitsPerSecond); | ||
|
||
if (filledWithToken) { | ||
// set storedPermits | ||
setField(rateLimiter, "storedPermits", permitsPerSecond * maxBurstSeconds); | ||
} | ||
|
||
return rateLimiter; | ||
} | ||
|
||
private static boolean setField(Object targetObject, String fieldName, Object fieldValue) { | ||
Field field; | ||
try { | ||
field = targetObject.getClass().getDeclaredField(fieldName); | ||
} catch (NoSuchFieldException e) { | ||
field = null; | ||
} | ||
Class superClass = targetObject.getClass().getSuperclass(); | ||
while (field == null && superClass != null) { | ||
try { | ||
field = superClass.getDeclaredField(fieldName); | ||
} catch (NoSuchFieldException e) { | ||
superClass = superClass.getSuperclass(); | ||
} | ||
} | ||
if (field == null) { | ||
return false; | ||
} | ||
field.setAccessible(true); | ||
try { | ||
field.set(targetObject, fieldValue); | ||
return true; | ||
} catch (IllegalAccessException e) { | ||
return false; | ||
} | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
vjkit/src/test/java/com/vip/vjtools/vjkit/concurrent/RateLimiterUtilTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package com.vip.vjtools.vjkit.concurrent; | ||
|
||
import java.lang.reflect.Field; | ||
|
||
import org.junit.Assert; | ||
import org.junit.Test; | ||
|
||
import com.google.common.util.concurrent.RateLimiter; | ||
|
||
public class RateLimiterUtilTest { | ||
@Test | ||
public void testCreate() throws Exception { | ||
RateLimiter rateLimiter = RateLimiterUtil.create(20000, 0.1); | ||
|
||
Class superClass = rateLimiter.getClass().getSuperclass(); | ||
Field field = superClass.getDeclaredField("storedPermits"); | ||
field.setAccessible(true); | ||
|
||
Assert.assertEquals(2000, (int) field.getDouble(rateLimiter)); | ||
} | ||
} |