文章目录
- 介绍
- 算法原理
- 适用场景
- 令牌通算法实现
- 限流算法
介绍
令牌桶算法是网络流量整形(Traffic Shaping)和速率限制(Rate Limiting)中最常使用的一种算法。典型情况下,令牌桶算法用来控制发送到网络上的数据的数目,并允许突发数据的发送。
算法原理
令牌桶算法基于以下核心概念:
令牌桶:一个虚拟的容器,用来存放固定数量的令牌。
令牌填充速率:系统以固定的速率向桶中添加令牌。
令牌消耗:每当一个数据包发送时,就从桶中移除一个k如果桶中没有令牌,数据包将被延迟发送或丢弃,直到桶中有足够的令牌。
适用场景
网络带宽管理:控制用户的网络流量,防止滥用。
API速率限制:限制API调用频率,保护后端服务。
云服务提供商:为不同级别的用户提供不同速率的服务。
任务调度:限制任务执行的速率,避免资源争用。
令牌通算法实现
package com.schdule.util;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class TokenBucket {
/**
* 桶的最大容量
*/
private int capacity;
/**
* 当前桶的令牌数
*/
private AtomicInteger tokens;
/**
* 令牌通的生成速率
*/
private int refillRate;
/**
* 上次填充令牌的时间
*/
private long lastRefillTimestamp;
public TokenBucket(int capacity, int refillRate) {
this.capacity = capacity;
this.tokens = new AtomicInteger(capacity);
this.refillRate = refillRate;
this.lastRefillTimestamp = System.nanoTime();
}
public synchronized boolean tryConsuse(){
refill();
if(tokens.get()>0){
tokens.decrementAndGet();
return true;
}
return false;
}
/**
* 填充令牌,根据时间间隔计算应该添加多少令牌
*/
public void refill(){
long now=System.nanoTime();
long timeSinceLastRefill = now - lastRefillTimestamp;
long tokensToAdd = timeSinceLastRefill * refillRate / TimeUnit.SECONDS.toNanos(1);
if(tokensToAdd>0){
int newTokenCount=Math.min(capacity,tokens.get()+(int)tokensToAdd);
tokens.set(newTokenCount);
lastRefillTimestamp=now;
}
}
public static void main(String[] args) throws InterruptedException {
// 创建一个容量为10,速率为每秒2个令牌的令牌桶
TokenBucket tokenBucket = new TokenBucket(10, 2);
// 模拟多个请求,每隔500毫秒尝试一次
for (int i = 0; i < 20; i++) {
boolean allowed = tokenBucket.tryConsuse();
System.out.println("Request " + (i + 1) + (allowed ? " allowed" : " denied"));
Thread.sleep(500);
}
}
}
限流算法
1.计数器算法是最简单也是最容易实现的限流算法。它通过维护一个计数器,每当有请求到达时,计数器加一,如果计数器的值超过了预设的阈值,则拒绝新的请求。这种算法实现简单,但容易受到突发流量的影响,因为请求可能会在同一时间窗口内集中到达,导致计数器迅速达到上限。
2.滑动窗口算法是对计数器算法的改进,通过将时间划分为多个小窗口,每个小窗口内限制请求的数量。与计数器算法相比,滑动窗口算法能够更好地处理突发流量,因为它允许在每个小窗口内有一定的请求量,而不会因为一个时间点的请求过多而导致整个时间窗口的请求被拒绝。
3.令牌桶算法通过控制令牌的生成速度来限制请求的处理速度。所有请求在处理前都需要获取一个可用的令牌。令牌以一定的速率生成,当桶满时,新生成的令牌会被丢弃或拒绝。这种算法能够有效地限制请求的处理速率,即使面对突发流量也能保持一定的服务能力。
4.漏桶算法可以看作是一个具有固定容量的请求队列,请求以一定的速率流入和流出。当请求流入的速度超过流出速度时,多余的请求会被丢弃。漏桶算法能够平滑地处理请求,防止突发流量对系统造成过大压力。