限流算法——固定窗口、滑动窗口、漏桶、令牌桶

本文系统讲解固定窗口、滑动窗口、漏桶和令牌桶四种限流算法的原理、实现逻辑及适用场景。固定窗口存在临界突刺问题;滑动窗口通过细分时间片缓解该问题;漏桶以恒定速率处理请求,适合强稳定性要求场景;令牌桶支持突发流量,允许空闲期积攒令牌。二者在流量整形、响应延迟和资源利用率上存在本质差异。

1. 计数器算法(固定窗口 → 滑动窗口)

把时间切成固定长度的格子,比如每 1 秒一格,每格维护一个计数器。请求进来就加一,超过阈值就拒绝,进入下一格时清零。

long windowStart; int count; int limit = 100;
synchronized boolean tryAcquire() {
    long now = System.currentTimeMillis();
    if (now - windowStart >= 1000) { windowStart = now; count = 0; }
    return ++count <= limit;
}

致命缺陷是临界突刺。假设限流每秒 100 个,有人在 0.9s 到 1.0s 之间打进 100 个,又在 1.0s 到 1.1s 之间打进 100 个。两个窗口各自都没超限,但在这 0.2 秒里系统实际扛了 200 个请求,是限额的 2 倍。这样就会导致限流实际上没有限住

滑动窗口就是为了修这个问题。它把 1 秒再切成 N 个小格(比如 10 个 100ms),统计时只看“当前时刻往前推 1 秒”覆盖的那些小格之和。窗口随时间一格一格往前滑,临界突刺被大大削弱。小格切得越细越精确,代价是内存和计算更多。极端情况下可以记录每个请求的时间戳(滑动日志),这样最精确,但也最费内存。

计数器类算法的本质:只管总量,不管请求在时间上的分布。

2. 漏桶算法(Leaky Bucket)

一个底部有小孔的桶:请求像水一样从上面倒进来,桶底以恒定速率往外漏,漏出去的请求才被处理。桶满了,新来的水就溢出,也就是请求被拒绝。

它的核心特点是:不管输入多猛,输出永远是匀速的。它是一个流量整形器,把突发流量“削峰填谷”成平滑流量。

long lastLeak; double water; int capacity = 100; double rate = 10; // 每秒漏10个
synchronized boolean tryAcquire() {
    long now = System.currentTimeMillis();
    water = Math.max(0, water - (now - lastLeak) / 1000.0 * rate); // 先算漏掉了多少
    lastLeak = now;
    if (water + 1 <= capacity) { water++; return true; }
    return false;
}

优点:保护下游效果最好,适合下游处理能力固定、经不起任何抖动的场景,比如调用第三方接口、写数据库。

缺点:太死板。即使系统此刻很空闲,突发请求也只能排队慢慢漏,不能利用空闲资源快速处理,响应延迟会变大。

3. 令牌桶算法(Token Bucket)

反过来想:系统以恒定速率往桶里放令牌,桶有容量上限,满了就不再放。请求来了先去桶里拿一个令牌,拿到才能被处理,拿不到就被拒绝或等待。

与漏桶的关键区别在于:空闲时令牌会攒起来。突发流量到来时,可以一次性消耗掉攒下的全部令牌,瞬间放行一批请求。所以令牌桶限制的是平均速率,同时允许一定程度的突发,突发上限就是桶的容量。

long lastRefill; double tokens; int capacity = 100; double rate = 10; // 每秒放10个
synchronized boolean tryAcquire() {
    long now = System.currentTimeMillis();
    tokens = Math.min(capacity, tokens + (now - lastRefill) / 1000.0 * rate); // 懒加载补令牌
    lastRefill = now;
    if (tokens >= 1) { tokens--; return true; }
    return false;
}

注意一个实现细节:真实代码不会开一个定时线程去放令牌,而是在每次请求时根据时间差懒计算应该补多少。上面的漏桶也是同样的思路。Guava 的 RateLimiter 就是令牌桶,还额外支持预热(SmoothWarmingUp),让系统冷启动时逐步放量。

漏桶 vs 令牌桶

漏桶令牌桶
控制的对象流出速率流入速率
突发流量不允许,强制匀速允许,最多突发“桶容量”个
空闲后的表现和平时一样慢能一口气处理一批
视角保护下游(我不能被压垮)保护自己,同时尽量多干活
典型应用调用外部接口、消息匀速消费API 网关、Guava RateLimiter

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值