import time from collections import defaultdict from typing import Optional class TokenBucket: """令牌桶限流器(每个 key 独立)""" def __init__(self, rate: float, burst: int): self.rate = rate # 每秒令牌数 self.burst = burst # 最大令牌数 self._tokens = defaultdict(float) self._last = defaultdict(float) def allow(self, key: str) -> bool: """返回 True 表示允许请求,False 表示限流""" now = time.time() # 补充令牌 last = self._last.get(key, now) elapsed = now - last self._last[key] = now self._tokens[key] = min(self.burst, self._tokens.get(key, self.burst) + elapsed * self.rate) if self._tokens[key] >= 1.0: self._tokens[key] -= 1.0 return True return False class RateLimiter: """多 key 限流器,qps<=0 时放行""" def __init__(self, qps: int = 0, burst: int = 0): self.qps = qps self.burst = burst if burst > 0 else qps self._bucket = TokenBucket(rate=qps, burst=self.burst) if qps > 0 else None def allow(self, key: str) -> bool: if self._bucket is None: return True return self._bucket.allow(key) def active_buckets(self) -> int: """返回当前活跃的 key 数量(近似)""" if self._bucket is None: return 0 return len(self._bucket._tokens)