# DRF Throttling에서 “scope” 쓰는 두 가지 방식 비교: ScopedRateThrottle vs UserRateThrottle 상속 DRF에서 scope 기반 throttling을 걸 때 자주 나오는 두 패턴이 있습니다. * **방식 A**: `UserRateThrottle`(또는 `SimpleRateThrottle`)을 상속해 **scope가 박힌 커스텀 클래스**를 만들고, 뷰에 `throttle_classes`로 직접 붙인다. * **방식 B**: `DEFAULT_THROTTLE_CLASSES`에 `ScopedRateThrottle`을 등록해두고, 뷰에는 `throttle_scope = "login"`만 적는다. 질문처럼 “결국 동일한 효과 아닌가?”에 대한 답부터 하면: > **단일 속도 제한을 ‘유저ID(또는 비로그인 IP) + scope’ 기준으로 걸겠다**는 수준에서는, **결과가 거의 동일**합니다. > 다만 **적용 방식(실수 방지), 확장성(복수 정책/커스텀 기준), 코드 구조(설정 중심 vs 코드 중심)**에서 차이가 나서 선택 기준이 생깁니다. --- ## 공통점: 둘 다 “scope + (user id or IP)”로 키를 만든다 {#sec-431a00e0f2d6} * `ScopedRateThrottle`은 뷰에 `throttle_scope`가 있으면 **scope + 유저ID/IP**로 키를 구성하고, `DEFAULT_THROTTLE_RATES`에서 해당 scope rate를 찾아 적용합니다. * `UserRateThrottle`도 기본적으로 인증 유저는 **user id**, 비인증은 **IP**를 기준으로 제한하며, 여러 개를 쓰려면 클래스를 상속해 scope를 다르게 두는 형태를 DRF가 공식 예시로 제시합니다. --- ## 차이 1) “어디에 scope를 적느냐”: 뷰 속성 vs 클래스 속성 {#sec-d624b1b24a23} ### 방식 A: 클래스에 scope를 고정(명시적) {#sec-8806ad9d3f5f} ```python from rest_framework.throttling import UserRateThrottle from rest_framework.views import APIView class CustomDomainSaveThrottle(UserRateThrottle): scope = "custom_domain_save" class SaveCustomDomainView(APIView): throttle_classes = [CustomDomainSaveThrottle] ``` * scope가 **클래스에 고정**됩니다. * 뷰는 “이 클래스 쓰겠다”만 선언하면 끝. * 실수로 scope 문자열을 뷰마다 오타내는 케이스가 줄어듭니다(클래스명이 사실상 문서 역할). ### 방식 B: 뷰에 scope만 달고, 공용 throttle이 해석(설정 중심) {#sec-21174dce63ed} ```python REST_FRAMEWORK = { "DEFAULT_THROTTLE_CLASSES": [ "rest_framework.throttling.ScopedRateThrottle", ], "DEFAULT_THROTTLE_RATES": { "login": "5/min", } } from rest_framework.views import APIView class LoginView(APIView): throttle_scope = "login" ``` * scope가 **뷰에 직접** 들어갑니다. * 공통 throttle(`ScopedRateThrottle`)이 “이 뷰는 login 스코프네?” 하고 설정에서 rate를 찾아 씁니다. * 코드가 짧고, settings에서 정책을 한눈에 관리하기 좋습니다. --- ## 차이 2) “적용을 누가 보장하느냐”: 기본 등록 vs 뷰별 장착 {#sec-693e9b27f525} ### 방식 B의 포인트(오해가 많음) {#sec-579edda7168e} `DEFAULT_THROTTLE_CLASSES`에 `ScopedRateThrottle`을 넣어도, **`throttle_scope`가 없는 뷰에는 적용되지 않습니다.** 즉 “전역에 넣으면 전체 API가 다 막힐까?” 걱정은 보통 필요 없습니다. ### 반대로 방식 A의 강점 {#sec-1d7d8c13bc83} 전역 설정을 건드리지 않고도, **특정 뷰에만** 원하는 throttle을 “장착”할 수 있습니다. (팀/서비스 구조상 settings를 크게 못 만지는 경우나, 특정 앱/엔드포인트만 강제하고 싶을 때 편합니다.) --- ## 차이 3) 확장성: “단일 제한”을 넘어가면 A가 유리해진다 {#sec-76818ce0201b} 둘이 거의 같아 보이는 구간은 “한 뷰에 한 스코프, 한 속도 제한”까지입니다. 그 다음부터는 차이가 벌어집니다. ### 1) “버스트 + 지속” 같이 **복수 throttle**을 한 뷰에 걸고 싶을 때 {#sec-c0ea02305999} DRF 문서도 여러 `UserRateThrottle`을 동시에 쓰는 패턴(버스트/서스테인)을 예시로 듭니다. ```python class Burst(UserRateThrottle): scope = "burst" class Sustained(UserRateThrottle): scope = "sustained" class SearchView(APIView): throttle_classes = [Burst, Sustained] ``` `ScopedRateThrottle`만으로는 “한 뷰에 스코프를 2개”를 자연스럽게 표현하기가 어렵고, 결국 **클래스가 필요**해집니다(또는 커스텀 구현). ### 2) “누구를 기준으로 제한할지”가 바뀌는 순간 {#sec-39de8e67072d} `ScopedRateThrottle`은 기본적으로 **user id / IP** 축에서 움직입니다. 그런데 실무에서는 이런 요구가 금방 나옵니다. * 로그인: **IP + username 조합**으로 제한하고 싶다(계정 타겟 공격 대응) * 조직/테넌트: **tenant_id 기준**으로 묶어서 제한하고 싶다 * API Key: **키 단위**로 제한하고 싶다 이건 결국 `get_cache_key()` 같은 로직 커스텀이 필요해져서 **방식 A(상속/커스텀 클래스)**로 자연스럽게 이동합니다. (DRF도 커스텀 throttle을 권장하는 지점이 이쪽입니다.) --- ![API연결을 여는 2개의 열쇠](/media/editor_temp/6/e98f026a-a38e-43ca-8c86-fa7966dd3cdf.png) ## 그래서 뭘 쓰면 좋을까? {#sec-1cf080d47909} ### 대부분의 “뷰별 rate limit”이면 → 방식 B(ScopedRateThrottle) 추천 {#sec-924ae91c07d2} * 코드 최소화 * settings에서 정책 일괄 관리 * 뷰에는 `throttle_scope`만 적으면 끝 * scope 없는 뷰에는 적용 안 됨 ### 아래 중 하나라도 해당하면 → 방식 A(상속/커스텀 클래스) 추천 {#sec-335f8d95a231} * 한 뷰에 **버스트+지속** 등 **복수 제한**을 동시에 걸고 싶다 * “user/IP”가 아닌 **커스텀 기준**(username+IP, tenant, API key 등)이 필요하다 * 전역 설정을 건드리기 어렵고 **특정 뷰에만 강제 장착**하고 싶다 * 클래스명으로 정책을 “문서화”하고 싶다(읽는 사람이 바로 의도를 파악) **관련 글:** - [DRF Throttling 완전 정복: 설정, 적용, 커스텀 가이드](/ko/whitedec/2026/1/26/drf-throttling-complete-guide/)