常见的限流算法分析
限流在我们日常生活中经常见到,如火车站门口的栏杆、一些景点的门票只出售一定的数量 等等。在我们的开发中也用到了这种思想。
为什么要限流
🏫在保证可用的情况下尽可能多增加进入的人数,其余的人在排队等待,或者返回友好提示,保证里面的进行系统的用户可以正常使用, 防止系统雪崩。
限流算法
🌴🌴限流算法很多,常见的有三类,分别是 计数器算法 、漏桶算法、令牌桶算法 。
(1)计数器:
在一段时间间隔内,处理请求的最大数量固定,超过部分不做处理。
(2)漏桶:
漏桶大小固定,处理速度固定,但请求进入速度不固定(在突发情况请求过多时,会丢弃过多的请求)。
(3)令牌桶:
令牌桶的大小固定,令牌的产生速度固定,但是消耗令牌(即请求)速度不固定(可以应对一些某些时间请求过多的情况);每个请求都会从令牌桶中取出令牌,如果没有令牌则丢弃该次请求。
计数器限流
🍺在一段时间间隔内,处理请求的最大数量固定,超过部分不做处理。
举个🌰,比如我们规定对于A接口,我们1分钟的访问次数不能超过100次。
那么我们可以这么做:
🎈在一开 始的时候,我们可以设置一个计数器counter,每当一个请求过来的时候,counter就加1,如果counter的值大于100并且该请求与第一个请求的间隔时间还在1分钟之内,那么说明请求数过多,拒绝访问;
🍬如果该请求与第一个请求的间隔时间大于1分钟,且counter的值还在限流范围内,那么就重置 counter,就是这么简单粗暴。
代码实现: 😎
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
//计数器 限流
public class CounterLimiter {
//起始时间
private static long startTime = System.currentTimeMillis();
//时间间隔1000ms
private static long interval = 1000;
//每个时间间隔内,限制数量
private static long limit = 3;
//累加器
private static AtomicLong accumulator = new AtomicLong();
/**
* true 代表放行,请求可已通过
* false 代表限制,不让请求通过
*/
public static boolean tryAcquire() {
long nowTime = System.currentTimeMillis();
//判断是否在上一个时间间隔内
if (nowTime < startTime + interval) {
//如果还在上个时间间隔内
long count = accumulator.incrementAndGet();
if (count <= limit) {
return true;
} else {
return false;
}
} else {
//如果不在上一个时间间隔内
synchronized (CounterLimiter.class) {
//防止重复初始化
if (nowTime > startTime + interval) {