在高并发中,有三把利器来保护系统:缓存、降级和限流。那么何为限流,就是限制流量,对系统的出入流量进行控制,防止大流量出入,导致资源不足,系统不稳定。
常见的三种限流算法:计数器算法,滑动窗口,令牌桶算法
1.计数器算法
比如规定,对于A接口来说,我们一分钟的访问次数不能超过100次。那么我们可以这么做,在一开始的时候,我们可以设置一个计数器,每当一个请求过来的时候,计数器加一,如果计数器值大于100且并且该请求与第一次请求的间隔还在一分钟之内。那么说明请求过多;如果该请求与第一个请求的间隔大于1分钟,且计数器值还在限流器范围内。那么就重置计数器。
public class CounterTest {
public long timeStamp = getNowTime();
public int reqCount = 0;
public final int limit = 100; // 时间窗口内最大请求数
public final long interval = 1000; // 时间窗口ms
public boolean grant() {
long now = getNowTime();
if (now < timeStamp + interval) {
// 在时间窗口内
reqCount++;
// 判断当前时间窗口内是否超过最大请求控制数
return reqCount <= limit;
} else {
timeStamp = now;
// 超时后重置
reqCount = 1;
return true;
}
}
public long getNowTime() {
return System.currentTimeMillis();
}
}
优点:能够实现控制并发数的效果
缺点:使用场景单一,适用单机,一般用来对入流量进行控制
2.滑动窗口
roling windows

上图中,整个红色的矩形表示一个时间窗口,在我们的例子中,一个时间窗口就是一个分钟,然后我们将时间窗口进行划分,比如途中,我们就将滑动窗口化成6格,所以每格代表10秒钟。每过10秒钟,我们的时间窗口就会往右滑动一格。每一个格子都有自己对应独立的计数器,比如当一个请求在0:35秒的时候到达,那么0:30~0:39对应的计数器就会加1
当0:59到达100格请求会落在灰色格子里,而1:00到达的请求会落在橘黄色的格子中。当时间到达1:00时,我们的窗口会往右移动一格,那么此时时间窗口内的总请求数量一共是200个,超过了限定的100个,所以此时能够检测出来触发了限流。
--- 资源唯一标识
local key = KEYS[1]
--- 时间窗最大并发数
local max_window_concurrency = tonumber(ARGV[1])
--- 时间窗
local window = tonumber(ARGV[2])
--- 时间窗内当前并发数
local curr_window_concurrency = tonumber(redis.call('get', key) or 0)
if current + 1 > limit then
return false
else
redis.call("INCRBY", key,1)
if window > -1 then
redis.call("expire", key,window)
end
return true
end
优点: 通过时间窗最大请求数可以直接换算出最大的QPS(QPS = 请求数/时间窗)
缺点: 可能出现流量不平滑,时间窗内一小段流量占比特别大。
3.令牌桶
1)所有请求在处理之前都需要拿到一个可用的令牌才会被处理
2)根据限流大小,设置按照一定速率往桶里添加令牌
3)桶设置最大的放置令牌限制,当桶满时,新添加的令牌就被丢弃或者拒绝
4)请求到达后首先要获取令牌桶中的令牌,拿着令牌才可以进行其他的业务逻辑,处理业务逻辑后,将令牌直接删除
5) 令牌桶右最低限额,当桶中的令牌达到最低限额的时候,请求处理完之后将不会删除令牌,以此保证足够的限流

博客来源:
https://www.cnblogs.com/linjiqin/p/9707713.html
https://mp.weixin.qq.com/s/3KF7Rcy5y3_RNFQZe4HX5Q