正在加载,请稍候…

系统设计:分布式限流器

设计一个用于 API 的分布式限流器。学习令牌桶、漏桶和滑动窗口算法,Redis 实现以及大规模处理边缘情况。

系统设计:分布式限流器

系统设计:分布式限流器

算法比较

令牌桶:允许突发到桶容量,平滑平均速率
漏桶:以恒定速率处理,队列吸收突发
固定窗口:简单但允许在窗口边界出现 2 倍突发
滑动窗口:更精确,防止边界突发

系统设计:分布式限流器示意图

令牌桶实现(Redis + Lua)

local key = KEYS[1]
local capacity = tonumber(ARGV[1])
local refill_rate = tonumber(ARGV[2])
local requested = tonumber(ARGV[3])
local now = tonumber(ARGV[4])

local bucket = redis.call('HMGET', key, 'tokens', 'last_refill')
local tokens = tonumber(bucket[1]) or capacity
local last_refill = tonumber(bucket[2]) or now

local elapsed = now - last_refill
local new_tokens = math.min(capacity, tokens + elapsed * refill_rate)

if new_tokens >= requested then
  redis.call('HMSET', key, 'tokens', new_tokens - requested, 'last_refill', now)
  redis.call('EXPIRE', key, math.ceil(capacity / refill_rate) + 1)
  return {1, math.floor(new_tokens - requested)}
else
  redis.call('HMSET', key, 'tokens', new_tokens, 'last_refill', now)
  return {0, math.floor(new_tokens)}
end

系统设计:分布式限流器示意图

滑动窗口(使用有序集合)

async function slidingWindowRateLimit(userId: string, limit: number, windowMs: number): Promise<boolean> {
  const key = `sw:${userId}`;
  const now = Date.now();
  const windowStart = now - windowMs;

  const pipeline = redis.multi();
  pipeline.zRemRangeByScore(key, '-inf', windowStart.toString());
  pipeline.zCard(key);
  pipeline.zAdd(key, { score: now, value: `${now}:${Math.random()}` });
  pipeline.pExpire(key, windowMs);

  const results = await pipeline.exec();
  const count = results[1] as number;
  return count < limit;
}

系统设计:分布式限流器示意图

多层限流

async function multiTierLimit(userId: string): Promise<void> {
  const limits = [
    { key: `sec:${userId}`, limit: 10, window: 1000 },
    { key: `min:${userId}`, limit: 100, window: 60000 },
    { key: `hour:${userId}`, limit: 1000, window: 3600000 },
  ];

  for (const { key, limit, window } of limits) {
    const allowed = await slidingWindowRateLimit(key, limit, window);
    if (!allowed) throw new TooManyRequestsError('Rate limit exceeded');
  }
}

API 网关中间件

app.use(async (req, res, next) => {
  const identifier = req.user?.id || req.ip;
  const result = await limiter.isAllowed(identifier, 100, 60);

  res.setHeader('X-RateLimit-Limit', 100);
  res.setHeader('X-RateLimit-Remaining', result.remaining);

  if (!result.allowed) {
    return res.status(429).json({ error: 'Too Many Requests' });
  }
  next();
});

分布式限流器是保护大规模 API 的核心基础设施组件。