限流

  1. 定时清除 (1分钟一清除)

    1. 实现简单
    2. 对于边界值,如59秒和下一秒会有问题,会得到一个请求限制速率的2倍
  2. 滑动窗口(10秒一清除)

    1. 是定时清除的一个优化,缩小了清除粒度但是还是有问题。
  3. 漏桶算法 (桶容量 + 桶流速度) https://github.com/uber-go/ratelimit

    • 超过桶的容量就要涉及到排队或拒绝了
    1. 不支持小流量激增
  4. 令牌桶算法(定时放入桶中令牌) https://github.com/juju/ratelimit

    1. 支持小流量并发激增

分布式限流则可用于 Redis + Lua脚本实现,其原理几乎差不多。

local key = "rate.limit:" .. KEYS[1] --限流KEY
local limit = tonumber(ARGV[1])        --限流大小
local current = tonumber(redis.call('get', key) or "0")
if current + 1 > limit then --如果超出限流大小
   return 0
else  --请求数+1,并设置1秒过期
   redis.call("INCRBY", key,"1")
   redis.call("expire", key,"1")
   return current + 1
end

再用相应的语言调用脚本。

  • Java代码传入key和最大的限制limit参数进lua脚本
  • 执行lua脚本(lua脚本判断当前key是否超过了最大限制limit)
    • 如果超过,则返回0(限流)
    • 如果没超过,返回1(程序继续执行)

参考资料