속도 제한기(Rate Limiter)는 클라이언트 요청 빈도를 제어해 API 남용 방지, DDoS 방어, 비용 관리에 사용되는 시스템이다.
| 알고리즘 | 설명 | 장점 | 단점 |
|---|
| Token Bucket | 토큰 생성, 요청시 소비 | 버스트 허용 | 버스트 제어 어려움 |
| Leaky Bucket | 고정 속도로 처리 | 일정한 출력 | 버스트 거부 |
| Fixed Window Counter | 시간 창 카운터 | 간단 | 창 경계 버스트 |
| Sliding Window Log | 타임스탬프 로그 | 정확 | 메모리 많이 사용 |
| Sliding Window Counter | 혼합 방식 | 정확+효율적 | 구현 복잡 |
Token Bucket 구현
python
import time
import threading
class TokenBucket:
def __init__(self, capacity: int, refill_rate: float):
self.capacity = capacity # 최대 토큰 수
self.tokens = capacity # 현재 토큰
self.refill_rate = refill_rate # 초당 토큰 추가량
self.last_refill = time.time()
self.lock = threading.Lock()
def allow_request(self) -> bool:
with self.lock:
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 요청
limiter = TokenBucket(capacity=100, refill_rate=100/60)
Redis 기반 분산 속도 제한기
python
import redis
import time
redis_client = redis.Redis()
def is_rate_limited(user_id: str, limit: int, window: int) -> bool:
"""Sliding Window Counter 방식"""
key = f"rate:{user_id}"
now = time.time()
window_start = now - window
pipe = redis_client.pipeline()
# 오래된 요청 제거
pipe.zremrangebyscore(key, 0, window_start)
# 현재 요청 수 조회
pipe.zcard(key)
# 현재 요청 추가
pipe.zadd(key, {str(now): now})
# TTL 설정
pipe.expire(key, window)
_, count, _, _ = pipe.execute()
return count >= limit
# 1분에 100 요청 제한
if is_rate_limited("user:123", limit=100, window=60):
return {"error": "Too Many Requests"}, 429
응답 헤더
http
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1716825600
Retry-After: 30
관련 문서
- •[[url-shortener-design|URL 단축기 설계]]
- •[[notification-system|알림 시스템 설계]]
- •[[distributed-counter|분산 카운터]]