사용자 등급별/IP별 요청량을 제어하는 Throttling 정책 설계
API 서버의 안정성을 위해 특정 기간 동안 API 호출 횟수를 제한하는 Throttling 기술을 구현하고, 사용자 등급에 따라 차등적인 서비스 품질을 제공하는 방법
Throttling의 필요성
서버 안정성 확보: DDoS 공격 등 과도한 요청으로부터 서버 보호
공정한 자원 분배: 모든 사용자에게 공평한 API 사용 기회 제공
서비스 품질(QoS) 보장: 등급별 차등 서비스로 만족도 향상
비용 관리: 외부 API 호출 비용 절약
비즈니스 모델: 무료/유료 사용자 구분을 통한 수익 모델 구현
DRF 기본 Throttling 클래스
클래스명
대상
식별 기준
설명
AnonRateThrottle
비로그인 사용자
IP 주소
인증되지 않은 사용자 요청 제한
UserRateThrottle
로그인 사용자
User ID
인증된 사용자 요청 제한
ScopedRateThrottle
특정 API
뷰 scope
뷰마다 다른 제한 적용
기본 설정
# settings.py
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.AnonRateThrottle',
'rest_framework.throttling.UserRateThrottle',
],
'DEFAULT_THROTTLE_RATES': {
'anon': '100/day',
'user': '1000/hour',
}
}사용자 등급별 커스텀 Throttling 구현
시나리오
등급별 시간당 요청 제한
free: 100회/시간bronze: 500회/시간silver: 2,000회/시간gold: 10,000회/시간
비로그인 사용자: IP당 60회/시간
커스텀 Throttling 클래스
# throttling.py
from rest_framework.throttling import SimpleRateThrottle
class TierBasedRateThrottle(SimpleRateThrottle):
scope = 'user'
def get_cache_key(self, request, view):
if request.user and request.user.is_authenticated:
self.scope = getattr(request.user, 'tier', 'free')
ident = request.user.pk
else:
self.scope = 'anon'
ident = self.get_ident(request)
return self.cache_format % {
'scope': self.scope,
'ident': ident
}설정 등록
# settings.py
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': [
'a_project.throttling.TierBasedRateThrottle',
],
'DEFAULT_THROTTLE_RATES': {
'anon': '60/hour',
'free': '100/hour',
'bronze': '500/hour',
'silver': '2000/hour',
'gold': '10000/hour',
}
}실무 고려사항
프록시 환경에서의 IP 식별
# settings.py
NUM_PROXIES = 1 # 프록시 서버가 1개 있는 경우캐시 백엔드 설정
# settings.py
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
}
}특정 뷰에서 Throttling 비활성화
class HealthCheckView(APIView):
throttle_classes = [] # Throttling 적용 안함Last updated
