API 网关限流模式深度解析

David Ng | 2026-09-01T08:57:58 | Database, Security

对比令牌桶、漏桶、滑动窗口三种限流算法,结合 Kong、APISIX 网关配置以及 Redis + Lua 自定义限流实现。

# API 网关限流模式深度解析 ## 三种限流算法 ### 令牌桶(Token Bucket) ```python import time class TokenBucket: def __init__(self, capacity, refill_rate): self.capacity = capacity self.tokens = capacity self.refill_rate = refill_rate # tokens per second self.last_refill = time.time() def allow(self): now = time.time() elapsed = now - self.last_refill self.tokens = min(self.capacity, self.tokens + elapsed * self.refill_rate) self.last_refill = now if self.tokens >= 1: self.tokens -= 1 return True return False # 容量100,每秒补充10个 bucket = TokenBucket(capacity=100, refill_rate=10) ``` ### 滑动窗口计数器 ```python class SlidingWindowCounter: def __init__(self, window_size, max_requests): self.window_size = window_size self.max_requests = max_requests self.requests = [] def allow(self): now = time.time() cutoff = now - self.window_size self.requests = [t for t in self.requests if t > cutoff] if len(self.requests) < self.max_requests: self.requests.append(now) return True return False ``` ## Redis + Lua 分布式限流 ```lua -- rate_limit.lua local key = KEYS[1] local limit = tonumber(ARGV[1]) local window = tonumber(ARGV[2]) local now = tonumber(ARGV[3]) -- 清除过期记录 redis.call('ZREMRANGEBYSCORE', key, 0, now - window * 1000) local count = redis.call('ZCARD', key) if count < limit then redis.call('ZADD', key, now, now .. '-' .. math.random(1000000)) redis.call('PEXPIRE', key, window * 1000) return 1 -- allowed else return 0 -- rejected end ``` ## APISIX 配置 ```yaml routes: - uri: /api/* plugins: limit-req: rate: 100 # 每秒请求数 burst: 50 # 突发容量 rejected_code: 429 key_type: var key: remote_addr limit-count: count: 10000 # 窗口期总量 time_window: 3600 # 1小时窗口 rejected_code: 429 policy: redis redis_host: 10.0.1.20 redis_port: 6379 ``` ## 多层限流策略 ``` 用户层: 1000 req/hour per user (by JWT subject) IP 层: 100 req/min per IP API 层: 50 req/sec per endpoint 全局层: 10000 req/sec total ``` 限流不仅保护后端服务,也是防止 API 滥用和 DDoS 攻击的重要手段。建议返回标准的 `429 Too Many Requests` 响应和 `Retry-After` 头。

← Back to Blog