跳转至

限流有哪些方案?

一、为什么要限流

保护系统不被突发流量打挂。常见场景:秒杀、接口防刷、第三方调用配额。

二、常见算法

1. 固定窗口计数器

每分钟 100 个请求,到了就拒绝。

  • 优点:简单。
  • 缺点:窗口边界突刺(59s 来 100 个,0s 又来 100 个,1 秒内 200 个)。

2. 滑动窗口

把窗口切成小格,统计过去 N 小格。比固定窗口平滑,但仍有边界问题。

3. 漏桶(Leaky Bucket)

请求像水进桶,桶以固定速率出水。超出桶容量拒绝。

  • 特点:输出速率恒定
  • 缺点:突发流量不能及时处理。

4. 令牌桶(Token Bucket)

以固定速率往桶里放令牌,请求要拿到令牌才能通过。桶满了新令牌丢弃。

  • 特点:允许一定程度的突发(桶里攒了令牌,一次可以拿多个)。
  • Guava RateLimiter 就是令牌桶。
RateLimiter limiter = RateLimiter.create(100); // 100 QPS
if (limiter.tryAcquire()) {
    // 处理请求
} else {
    // 限流
}

5. 信号量(Semaphore)

限制并发数,不是速率。适合限制同时处理的请求数。

三、分布式限流

单机限流不够,多台机器要统一计数。

1. Redis + Lua

local key = KEYS[1]
local limit = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
local current = redis.call('INCR', key)
if current == 1 then
    redis.call('EXPIRE', key, window)
end
if current > limit then
    return 0
end
return 1

Lua 保证原子性。

2. Sentinel

阿里开源,支持:

  • 限流(QPS、线程数)。
  • 熔断降级。
  • 系统负载保护。
  • 控制台动态规则。

3. Gateway 层限流

在 Nginx / Spring Cloud Gateway 层做限流,挡住大部分流量。

四、限流后处理

  • 直接拒绝:返回 429。
  • 排队等待:请求进入队列,慢慢处理。
  • 降级:返回兜底数据。

五、常见维度

  • 用户 ID 限流:防刷。
  • IP 限流:防爬虫。
  • 接口维度:保护核心接口。
  • 全局限流:保护整个系统。

高频追问

  • 令牌桶 vs 漏桶:令牌桶允许突发,漏桶强制匀速。
  • 单机 vs 分布式:单机用 Guava,分布式用 Redis+Lua 或 Sentinel。