一、限流概念
阈值:在一个单位时间内允许的请求量。如QPS 限制为10,说明 1 秒内最多接受 10 次请求。
拒绝策略:超过阈值的请求的拒绝策略,常见的拒绝策略有直接拒绝、排队等待等。
一、限流算法
5种限流算法
1、固定窗口算法
2、滑动窗口算法
3、滑动日志算法
4、漏桶算法
5、令牌桶算法
1、固定窗口算法
固定窗口算法又叫计数器算法,比如:计算一秒内多少请求,过完一秒清空重新计数。每隔 1 秒重置计数器
缺点:遇到时间窗口的临界突变时,如 1s 中的后 500 ms 和第 2s 的前 500ms 时,虽然是加起来是 1s 时间,
却可以被请求 4 次。
实现方式:
1、Redis 中的固定窗口限流是使用 incr 命令实现的,incr 命令通常用来自增计数;
如果我们使用时间戳信息作为 key,自然就可以统计每秒的请求量了,以此达到限流目的。
2、滑动窗口算法
主要是对:固定窗口算法在遇到时间窗口的临界突变时问题改进。
实现方式:
实现原理,通过redis的zset数据结构来实现,比如我们设置的10秒内最多5个请求,请求进来,
我们把请求的时候实现作为分数,添加到zset里面去,那怎么判断有没有超过窗口限定数量呢,
通过当前时间减去10秒,那么zset集合中,就剩下10内请求的数量了,然后判断当前数量是否超过5个,
如果超过就拒绝,没有超过就添加,下次请求过来也是这样判断。
代码的话最好使用redis事务,或者lu a脚本解决。
方式二:
直接存到Zset里面去,在使用Zset的通过范围查询数据,比如下面命令
jedis.zadd(zsetName, 10.0, "member1");//存数据
jedis.zrangeByScoreWithScores(zsetName, minScore, maxScore);//按范围查数据
3、滑动日志算法
滑动日志算法是实现限流的另一种方法,这种方法比较简单。
基本逻辑就是记录下所有的请求时间点,新请求到来时先判断最近指定时间范围内的请求数量是否超过指定阈值,
由此来确定是否达到限流,这种方式没有了时间窗口突变的问题,限流比较准确,
缺点就是:要记录下每次请求的时间点,所以占用的内存较多。
4、漏桶算法
5、令牌桶算法
令牌桶的实现算法有:Guava
三、限流方案
1、Nginx限流
2、Gateway和Zuul
3、限流sentinel
4、Guava类里面的RateLimiter