admin 2025-08-07 15:34:00 世界杯专用足球

六种限流算法与原理详解

1. 固定窗口算法固定窗口算法原理:固定窗口算法通过在单位时间内维护一个计数器,限制在每个固定的时间段内请求通过的次数,以达到限流的效果。优点:算法实现简单,容易理解。缺点:不能应对突发流量,可能导致短时间内流量激增,从而影响服务稳定性。代码语言:java复制 public class FixedWindowRateLimiter {

private long windowSize; // 时间窗口大小,单位毫秒

private int maxRequestCount; // 允许通过请求数

private AtomicInteger count = new AtomicInteger(0); // 当前窗口通过的请求计数

private long windowBorder; // 窗口右边界

public FixedWindowRateLimiter(long windowSize, int maxRequestCount) {

this.windowSize = windowSize;

this.maxRequestCount = maxRequestCount;

windowBorder = System.currentTimeMillis() + windowSize;

}

public synchronized boolean tryAcquire() {

long currentTime = System.currentTimeMillis();

if (windowBorder < currentTime) {

windowBorder += windowSize;

count.set(0);

}

if (count.intValue() < maxRequestCount) {

count.incrementAndGet();

return true;

} else {

return false;

}

}

}2. 滑动窗口算法滑动窗口算法原理:滑动窗口算法在固定窗口的基础上进行了改进,将时间窗口划分为多个小块,每个小块维护独立的计数器,每次滑动时,减去前一个时间块内的请求数量,并添加一个新的时间块到末尾。优点:流量控制更精细,能够更平滑地处理请求。缺点:需要额外的存储空间来维护每一块时间内的计数器,实现相对复杂。代码语言:java复制 public class SlidingWindowRateLimiter {

private long windowSize; // 时间窗口大小,单位毫秒

private int shardNum; // 分片窗口数

private int maxRequestCount; // 允许通过请求数

private int[] shardRequestCount; // 各个窗口内请求计数

private int totalCount; // 请求总数

private int shardId; // 当前窗口下标

private long tinyWindowSize; // 每个小窗口大小,毫秒

private long windowBorder; // 窗口右边界

public SlidingWindowRateLimiter(long windowSize, int shardNum, int maxRequestCount) {

this.windowSize = windowSize;

this.shardNum = shardNum;

this.maxRequestCount = maxRequestCount;

shardRequestCount = new int[shardNum];

tinyWindowSize = windowSize / shardNum;

windowBorder = System.currentTimeMillis();

}

public synchronized boolean tryAcquire() {

long currentTime = System.currentTimeMillis();

if (currentTime > windowBorder) {

do {

shardId = (++shardId) % shardNum;

totalCount -= shardRequestCount[shardId];

shardRequestCount[shardId] = 0;

windowBorder += tinyWindowSize;

} while (windowBorder < currentTime);

}

if (totalCount < maxRequestCount) {

shardRequestCount[shardId]++;

totalCount++;

return true;

} else {

return false;

}

}

}3. 漏桶算法漏桶算法原理:漏桶算法通过以固定速率出水,将外部请求比作水,不断注入水桶中,如果水超过桶的最大容量则被丢弃,以此来控制数据的传输速率。优点:能够有效地控制数据的传输速率,平滑处理请求。缺点:不管系统负载如何,所有请求都得排队,可能导致系统资源的浪费。代码语言:java复制 public class LeakyBucketRateLimiter {

private int capacity; // 桶的容量

private AtomicInteger water = new AtomicInteger(0); // 桶中现存水量

private long leakTimeStamp; // 开始漏水时间

private int leakRate; // 水流出的速率,即每秒允许通过的请求数

public LeakyBucketRateLimiter(int capacity, int leakRate) {

this.capacity = capacity;

this.leakRate = leakRate;

}

public synchronized boolean tryAcquire() {

if (water.get() == 0) {

leakTimeStamp = System.currentTimeMillis();

water.incrementAndGet();

return water.get() < capacity;

}

long currentTime = System.currentTimeMillis();

int leakedWater = (int)((currentTime - leakTimeStamp) / 1000 * leakRate);

if (leakedWater != 0) {

int leftWater = water.get() - leakedWater;

water.set(Math.max(0, leftWater));

leakTimeStamp = System.currentTimeMillis();

}

if (water.get() < capacity) {

water.incrementAndGet();

return true;

} else {

return false;

}

}

}4. 令牌桶算法令牌桶算法原理:令牌桶算法通过系统以恒定的速度生成令牌,并将令牌放入令牌桶中,请求必须从令牌桶中获取一个令牌才能被处理,如果桶中没有令牌,则请求被限流。优点:允许一定程度的突发请求,能够限制服务调用的平均速率,同时允许一定程度的突发调用。缺点:无明显缺点,是较为理想的限流算法。代码语言:java复制 RateLimiter rateLimiter = RateLimiter.create(5);

for (int i = 0; i < 10; i++) {

double time = rateLimiter.acquire();

System.out.println("等待时间:" + time + "s");

}5. 中间件限流工具:Sentinel原理:Sentinel 是 Spring Cloud Alibaba 中的熔断限流组件,通过在服务层的方法上添加注解来实现限流。优点:适用于分布式、微服务架构,提供开箱即用的限流方法。缺点:需要引入额外的组件。代码语言:java复制 @Service

public class QueryService {

public static final String KEY = "query";

@SentinelResource(value = KEY, blockHandler = "blockHandlerMethod")

public String query(String name) {

return "begin query, name=" + name;

}

public String blockHandlerMethod(String name, BlockException e) {

e.printStackTrace();

return "blockHandlerMethod for Query : " + name;

}

}6. 网关限流工具:Spring Cloud Gateway原理:通过配置网关规则,使用 Redis 加 Lua 脚本的方式实现令牌桶算法进行限流。优点:可以灵活设置限流的维度,如请求路径、用户信息等。缺点:需要配置和维护 Redis。代码语言:java复制 @Component

public class PathKeyResolver implements KeyResolver {

public Mono resolve(ServerWebExchange exchange) {

String path = exchange.getRequest().getPath().toString();

return Mono.just(path);

}

}结论限流是确保系统稳定性的关键措施之一。文章介绍了六种限流方法,包括固定窗口算法、滑动窗口算法、漏桶算法、令牌桶算法、中间件限流和网关限流,各有优缺点,适用于不同的场景和架构。