限流防的是「突发流量把服务打挂」和「被刷」。
漏桶(Leaky Bucket)
请求进桶,桶以恒定速率出水,桶满了就拒绝或排队。
特点:流出速率恒定,能绝对限制住下游压力,但没法应对合理突发。
令牌桶(Token Bucket)
按固定速率往桶里放令牌,请求来了拿一个令牌才能过,拿不到就拒绝。
特点:允许突发——桶里攒的令牌可以一次性用掉。
实际业务中令牌桶更常用,因为用户连点几下不该被拒。
Redis + Lua 实现(必须原子)
local key = KEYS[1]
local rate = tonumber(ARGV[1]) -- 每秒生成令牌数
local cap = tonumber(ARGV[2]) -- 桶容量
local now = tonumber(ARGV[3])
local last, tokens = unpack(redis.call('HMGET', key, 'ts', 'tokens'))
tokens = tonumber(tokens) or cap
last = tonumber(last) or now
tokens = math.min(cap, tokens + (now - last) * rate)
if tokens < 1 then
return 0
end
redis.call('HMSET', key, 'ts', now, 'tokens', tokens - 1)
redis.call('EXPIRE', key, 60)
return 1
必须用 Lua:读-算-写三步要原子,否则并发下会超发。
限流了返回什么
HTTP 429,并带 Retry-After 告诉客户端多久后重试。
别返回 500——那会触发对方重试,反而雪上加霜。
限流粒度
按用户 ID 限比按 IP 准(公司出口 IP 会误伤一片人);
短信、支付这类重要接口单独设更低的阈值。
楼主 · 2026-09-28 14:37 · 浏览 7

