返回首页

接口限流 5 种算法详解:计数器 / 滑动窗口 / 令牌桶 / 漏桶 / Redis+Lua

📅 创建于 2026-05-19 🔄 更新于 2026-05-19 📝 182 字

接口限流 5 种算法详解

接口被刷怎么办?限流方案全攻略——从最简单的计数器到分布式 Redis+Lua 原子限流,5 种算法覆盖不同场景。

一、计数器(最简单)

统计单位时间内的请求数,超过阈值则拒绝。

// 简单实现(生产用 Redis)
if (redis.incr("rate:user:123") > 100) {
    return "请求太频繁,请稍后再试";
}
redis.expire("rate:user:123", 1); // 1 秒过期

⚠️ 缺点:临界点问题——0.9 秒时刷 100 次,1.1 秒时再刷 100 次,实际 1 秒内请求了 200 次。

二、滑动窗口(计数器升级版)

把时间切成多个小窗口,更精确地统计请求数。解决了计数器的临界点问题,但实现较复杂。

三、令牌桶(最推荐)

以固定速率往桶里放令牌,请求来了先拿令牌,拿到才放行。

  • 优点: 可以应对突发流量(桶里有令牌就能用)
  • 代表实现: Guava RateLimiter
RateLimiter limiter = RateLimiter.create(100); // 每秒 100 个令牌
if (!limiter.tryAcquire()) {
    return "系统繁忙,请稍后再试";
}

四、漏桶

请求像水滴一样进入漏桶,以固定速度流出。

  • 优点: 流量非常平滑
  • 缺点: 无法应对突发流量

五、Redis + Lua(分布式限流)

Lua 脚本保证原子性执行,适用于分布式场景。

-- Lua 脚本:原子性执行限流
local key = KEYS[1]
local limit = tonumber(ARGV[1])
local expire = tonumber(ARGV[2])

local current = tonumber(redis.call('get', key) or "0")
if current >= limit then
    return 0
end
current = redis.call('incr', key)
if current == 1 then
    redis.call('expire', key, expire)
end
return 1

限流维度选择

维度 适用场景
IP 限流 防止单个 IP 刷接口
用户 ID 限流 防止登录用户刷接口
接口限流 保护重要接口
全局限流 保护整个系统

关联页面

页面关联点
high-concurrency-four-strategies高并发四大手段概览(缓存/限流/削峰/幂等)——限流在高并发系统中的定位与作用
nginx-security-config-guideNginx 安全配置实战(连接层/请求层限流配置)
nginx-pre-launch-checklistNginx 上线前检查清单(限流/超时配置项)