限流策略指南

算法对比

令牌桶

以固定速率添加令牌。请求消耗令牌。允许突发到桶大小。

✓ 支持突发,平均速率平滑
漏桶

请求排队。以恒定速率处理,无论输入如何。输出非常平滑。

✓ 输出平滑,无突发
固定窗口

每时间窗口允许N个请求(如100/分钟)。窗口边界重置。简单但边界可能突发。

✓ 简单,易理解
滑动窗口

在滚动时间窗口内计数请求。比固定窗口更精确。内存使用更多。

✓ 精确,无边界突发

标准限流响应头

# Response headers (IETF draft standard)
RateLimit-Limit: 100        # max requests per window
RateLimit-Remaining: 45     # requests left
RateLimit-Reset: 1704067200 # Unix timestamp when window resets

# When limit exceeded: 429 Too Many Requests
HTTP/1.1 429 Too Many Requests
Retry-After: 30             # seconds to wait

Redis令牌桶(Go示例)

// Using go-redis with token bucket pattern
func rateLimitCheck(ctx context.Context, rdb *redis.Client, key string, limit int, window time.Duration) bool {
    pipe := rdb.Pipeline()
    now := time.Now().Unix()
    windowStart := now - int64(window.Seconds())

    // Remove expired entries
    pipe.ZRemRangeByScore(ctx, key, "-inf", strconv.FormatInt(windowStart, 10))
    // Count current window
    pipe.ZCard(ctx, key)
    // Add new request
    pipe.ZAdd(ctx, key, &redis.Z{Score: float64(now), Member: now})
    pipe.Expire(ctx, key, window)

    results, _ := pipe.Exec(ctx)
    count := results[1].(*redis.IntCmd).Val()
    return count < int64(limit)
}

不同API类型建议限制

API类型典型限制说明
公开读取API1000/hour未认证用户
认证API5000/hour每API key
写入/修改API100/minute每用户
登录端点10/minute防暴力破解
邮件/短信发送5/minute每用户每操作