有关于java算法的网址_大型网站限流算法的实现和改造

最近写了一个限流的插件,所以避免不了的接触到了一些限流算法。本篇文章就来分析一下这几种常见的限流算法

分析之前

依我个人的理解来说限流的话应该灵活到可以针对每一个接口来做。比如说一个类里面有5个接口,那么我的限流插件就应该能针对每一个接口就行不同的限流方案。所以呢,既然针对的每个接口所以就需要一个可以唯一标示这个接口的key(我取的是类名+方法名+入参)。

分布式限流强烈推荐使用redis+lua或者nginx+lua来实现。

这里用2个限流条件来做示例讲一下常见的限流算法:

接口1它10秒钟最大允许访问100次

接口2它10秒钟最大允许每个人访问100次。

计数器算法

这个算法可以说是限流算法中最简单的一种算法了。

核心思想

计数器算法的意思呢就是当接口在一个时间单位中被访问时,我就记下来访问次数,直到它访问的次数到达上限。

涉及变量

接口(key)

时间单位(expire)

允许访问多少次(limit)

访问次数(value)

条件一

当一个请求过来时,我们就会得到这个key。

1

2

3

4

5

6

7

8

9

if(存在key){

value++;

if(value>=limit){

不能访问

}

}else{

添加key,value为1

设置key过期时间为expire

}

条件二

既然条件一已经实现了,那条件二会复杂么 ?

相比于条件一来说就是同一个key对应了多个用户。那么我们只需要把key加上用户的信息就可以了。比如说 key_用户1、key_用户2。

漏桶算法

核心思想

漏桶算法的意思呢就是一个接口在一个时间单位中允许被访问次数是动态变化的(假如一分钟允许访问60次,那么从开始计时时不管有没有被访问第59秒只允许访问59次,30秒只允许30次)。为什么这样呢,因为有另外一个线程在进行递减操作

涉及变量

接口(key)

时间单位(expire)

允许访问多少次(limit)

递减间隔时间(interval)

递减步长(step)

剩余可访问次数(value)

key的访问时间(lastUpdateTime)

当前时间(nowTime)(注意nowTime的取值应为应用取得的时间而不是redis或者nginx取得的时间)

条件一

线程一:

1

2

3

4

5

6

7

8

if(存在key){

value--;

if(value<=0){

不能访问

}

}else{

添加key,设置value为limit

}

线程二:

1

2

3

while(过去interval时间){

所有key的value-step

}

条件二

参考计数器算法条件二实现。

算法升级

可以看到实现漏桶算法的话需要每隔interval时间都要另外一条线程去遍历所key的value去做递减操作,那么有没有什么办法可以省略这一步呢。答案是肯定有。

1

2

3

4

5

6

7

8

9

10

11

12

13

if(存在key){

value--;

if((nowTime-lastUpdateTime)>interval){

value=value-(nowTime-lastUpdateTime)/interval*step;

lastUpdateTime=nowTime;

}

if(value<=0){

不能访问

}

}else{

添加key,设置value为limit;

lastUpdateTime=nowTime;

}

令牌桶算法

核心思想

令牌桶算法呢,恰恰是和漏桶算法相反的一个算法,不过还是推荐你使用这个。这个算法的原理我不讲,我觉得聪明的你看了伪代码就明白了。

涉及变量

接口(key)

时间单位(expire)

允许访问多少次(limit)

递增间隔时间(interval)

递增步长(step)

当前可访问次数(value)

key的访问时间(lastUpdateTime)

当前时间(nowTime)(参照漏桶算法需要注意的点)

条件一

线程一:

1

2

3

4

5

6

7

8

if(存在key){

value++;

if(value>=limit){

不能访问

}

}else{

添加key,设置value为limit

}

线程二:

1

2

3

while(过去interval时间){

所有key的value+step

}

条件二

参考计算器算法条件二实现。

算法升级

参考漏桶算法升级实现。

代码

令牌桶算法是一种常见的限流算法,它可以控制请求的速率,防止系统被过多的请求压垮。下面是Java实现令牌桶算法的步骤和代码逻辑: 1. 定义一个令牌桶类,包含以下属性: - 最后一次令牌发放时间 - 桶的容量 - 令牌生成速度 - 当前令牌数量 2. 实现一个获取令牌的方法,该方法会在每次请求到来时被调用,具体实现如下: - 计算当前令牌数量 - 判断当前令牌数量是否足够 - 如果令牌数量不足,则拒绝请求 - 如果令牌数量足够,则领取令牌,并执行业务逻辑 3. 使用ScheduledExecutorService定时生成令牌,具体实现如下: - 每隔一段时间生成一定数量的令牌 - 如果令牌数量超过桶的容量,则不再生成令牌 下面是Java实现令牌桶算法的代码逻辑: ``` @Slf4j public class TokensLimiter { private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5); // 最后一次令牌发放时间 public long timeStamp = System.currentTimeMillis(); // 桶的容量 public int capacity = 10; // 令牌生成速度10/s public int rate = 10; // 当前令牌数量 public int tokens; public void acquire() { scheduledExecutorService.scheduleWithFixedDelay(() -> { long now = System.currentTimeMillis(); // 当前令牌数 tokens = Math.min(capacity, (int) (tokens + (now - timeStamp) * rate / 1000)); // 每隔0.5秒发送随机数量的请求 int permits = (int) (Math.random() * 9) + 1; log.info("请求令牌数:" + permits + ",当前令牌数:" + tokens); timeStamp = now; if (tokens < permits) { // 若不到令牌,拒绝 log.info("限流了"); } else { // 还有令牌,领取令牌 tokens -= permits; log.info("剩余令牌=" + tokens); } }, 1000, 500, TimeUnit.MILLISECONDS); } public static void main(String[] args) { TokensLimiter tokensLimiter = new TokensLimiter(); tokensLimiter.acquire(); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值