Guava RateLimiter 限流详解
- 手写令牌桶算法实现限流
public class TokenBucketDemo {
private static long time = System.currentTimeMillis();
private static int createTokenRate = 3;
private static int size = 10;
private static int tokens = 0;
public static boolean grant() {
long now = System.currentTimeMillis();
int in = (int) ((now - time) * createTokenRate);
tokens = Math.min(size, tokens + in);
time = now;
if (tokens > 0) {
--tokens;
return true;
} else {
return false;
}
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(new Runnable() {
@Override
public void run() {
if (grant()) {
System.out.println("执行业务逻辑");
} else {
System.out.println("限流");
}
}
}).start()
}
}
}
- Guava RateLimiter
基于令牌桶算法,我们只需要告诉RateLimiter系统限制的QPS是多少,那么RateLimiter将以这个速度往桶里面放入令牌,然后请求的时候,通过tryAcquire()方法向RateLimiter获取许可(令牌)。
令牌桶算法由于实现简单,且允许某些流量的突发,对用户友好,所以被业界采用地较多。当然我们需要具体情况具体分析,只有最合适的算法,没有最优的算法
public class LimitDemo {
public static ConcurrentHashMapresourceRateLimiter = new ConcurrentHashMap();
static {
createResourceLimiter("order", 50);
}
public static void createResourceLimiter(String resource, double qps) {
if (resourceRateLimiter.contains(resource)) {
resourceRateLimiter.get(resource).setRate(qps);
} else {
RateLimiter rateLimiter = RateLimiter.create(qps);
resourceRateLimiter.putIfAbsent(resource, rateLimiter);
}
}
public static void main(String[] args) {
for (int i = 0; i < 5000; i++) {
new Thread(new Runnable() {
@Override
public void run() {
if (resourceRateLimiter.get("order").tryAcquire(10, TimeUnit.MILLISECONDS)){
System.out.println("执行业务逻辑");
}else {
System.out.println("限流");
}
}
}).start();
}
}
}