Spring Boot 接口如何做限流?
前言
算法介绍
计数器法
public class CounterDemo {
public long timeStamp = getNowTime();
public int reqCount = 0;
public final int limit = 100; // 时间窗口内最大请求数
public final long interval = 60000; // 时间窗口ms
public boolean grant() {
long now = getNowTime();
if (now < timeStamp + interval) {
// 在时间窗口内
reqCount++;
// 判断当前时间窗口内是否超过最大请求控制数
return reqCount <= limit;
}
else {
timeStamp = now;
// 超时后重置
reqCount = 1;
return true;
}
}
private static Long getNowTime(){
return System.currentTimeMillis();
}
}
滑动窗口
public class CounterDemo {
public long timeStamp = getNowTime();
public int reqCount = 0;
public final int limit = 100; // 时间窗口内最大请求数
public final long interval = 6000; // 时间窗口6ms,6格
public boolean grant() {
long now = getNowTime();
if (now < timeStamp + interval) {
// 在时间窗口内
reqCount++;
// 判断当前时间窗口内是否超过最大请求控制数
return reqCount <= limit;
}
else {
timeStamp = now;
// 超时后重置
reqCount = 1;
return true;
}
}
private static Long getNowTime(){
return System.currentTimeMillis();
}
}
漏桶算法
public class LeakyDemo {
public long timeStamp = getNowTime();
public int capacity; // 桶的容量
public int rate; // 水漏出的速度
public Long water; // 当前水量(当前累积请求数)
public boolean grant() {
long now = getNowTime();
water = Math.max(0L, water - (now - timeStamp) * rate); // 先执行漏水,计算剩余水量
timeStamp = now;
if ((water + 1) < capacity) {
// 尝试加水,并且水还未满
water += 1;
return true;
}
else {
// 水满,拒绝加水
return false;
}
}
private static Long getNowTime(){
return System.currentTimeMillis();
}
}
令牌桶算法
public class TokenBucketDemo {
public long timeStamp = getNowTime();
public int capacity; // 桶的容量
public int rate; // 令牌放入速度
public Long tokens; // 当前令牌数量
public boolean grant() {
long now = getNowTime();
// 先添加令牌
tokens = Math.min(capacity, tokens + (now - timeStamp) * rate);
timeStamp = now;
if (tokens < 1) {
// 若不到1个令牌,则拒绝
return false;
}
else {
// 还有令牌,领取令牌
tokens -= 1;
return true;
}
}
private static Long getNowTime(){
return System.currentTimeMillis();
}
}
RateLimiter实现
@Slf4j
public class RateLimiterExample1 {
// 代表每秒最多2个
// guava限流采用的是令牌桶的方式
private static RateLimiter rateLimiter = RateLimiter.create(2);
public static void main(String[] args) {
for (int index = 0; index < 100; index++) {
// 单位时间内获取令牌
if (rateLimiter.tryAcquire(190, TimeUnit.MILLISECONDS)) {
handle(index);
}
}
}
private static void handle(int i) {
log.info("{}", i);
}
总结
计数器 VS 滑动窗口
漏桶算法 VS 令牌桶算法
作者 | bruce.yao
来源 | blog.csdn.net/yb223731/article/details/95460376
评论