📢 欢迎来到万事技术论坛!本站仅讨论合法编程技术话题,严禁外挂/作弊/黑产/盗版内容,违者封号。

精华接口限流:令牌桶与漏桶的区别和实现

ops_wang 进阶会员

限流防的是「突发流量把服务打挂」和「被刷」。

漏桶(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
yuki 进阶会员

「限流返回 429 而不是 500」这个细节太关键了。我们之前返回 500,
客户端的重试逻辑被触发,直接把流量放大了三倍,本来没事变成有事。

1楼 · 2026-09-28 14:37
dba_zhou 进阶会员

请问按用户限流的话,未登录用户怎么限?只能退回到 IP 吗?

2楼 · 2026-09-28 14:37
登录 后即可参与回复。