API 속도 제한 설명: 알고리즘, 헤더 및 429 오류 처리

  1. 홈
  2. 블로그
  3. 소프트웨어 개발

소프트웨어 개발

API 속도 제한 설명: 알고리즘, 헤더 및 429 오류 처리

비율 제한은 API를 과부하 및 남용으로부터 보호합니다. 우리가 실행한 시뮬레이션을 사용하여 주요 알고리즘이 어떻게 작동하는지, 좋은 429 응답이 어떤 모습인지, 클라이언트가 어떻게 물러서야 하는지 알아보세요.

읽는 시간 8분
API 속도 제한 설명: 알고리즘, 헤더 및 429 오류 처리

핵심 요약

  • 속도 제한은 클라이언트가 일정 기간 동안 만들 수 있는 요청 수를 제한합니다.
  • 토큰 버킷은 평균 속도를 적용하면서 짧은 버스트를 허용합니다.
  • 간단한 고정 창은 창 경계에서 두 배의 제한을 통과할 수 있습니다.
  • Retry-After 헤더와 함께 429 너무 많은 요청을 반환하고 클라이언트가 지터로 인해 백오프되도록 합니다.

하나의 버그가 있는 스크립트가 긴밀한 루프에서 API를 호출합니다. 제한이 없으면 다른 모든 사용자의 서비스 속도가 느려지거나 클라우드 비용이 많이 발생할 수 있습니다. API 속도 제한은 단일 클라이언트가 공정한 몫 이상을 취하지 못하도록 하는 가드레일입니다.

일반적인 알고리즘이 어떻게 작동하는지 보여주기 위해 우리는 작은 Python 버전을 작성하고 시뮬레이션된 요청 타이밍을 제공했습니다. 아래 출력은 해당 실행에서 나온 것입니다. 프로덕션 코드가 아닌 교육 모델이며 실제 게이트웨이에는 더 많은 기능이 있습니다.

속도 제한이란 무엇입니까?

속도 제한은 클라이언트당 요청 수를 계산하고 합의된 한도(예: 분당 100개 요청)를 초과하는 요청을 거부하거나 지연시킵니다. 관련 개념인 제한은 요청을 거부하는 것이 아니라 속도를 늦추는 것을 의미하는 경우가 많습니다. 할당량은 일반적으로 가격 책정 계획에서 월 10,000건의 통화와 같이 장기간에 걸쳐 더 큰 허용량입니다.

API에 필요한 이유

  • 안정성: 트래픽 급증이 데이터베이스나 다운스트림 서비스를 압도할 수 없습니다.
  • 공정성: 하나의 무거운 클라이언트가 다른 클라이언트를 굶길 수는 없습니다.
  • 보안: 제한은 무차별 로그인 시도 및 스크래핑 속도를 늦춥니다.
  • 비용 관리: AI 모델 호출과 같은 비용이 많이 드는 작업은 예산 범위 내에서 유지됩니다.

속도 제한은 OWASP API 보안 상위 10개 항목 중 무제한 리소스 소비에 대한 핵심 제어입니다. Postman을 사용한 API 테스트 가이드에서는 확인에 필요한 반복 요청을 보내는 방법을 보여줍니다.

토큰 버킷

최대 5개의 토큰을 담는 버킷을 상상해보세요. 각 요청에는 토큰이 필요합니다. 토큰은 초당 1개씩 다시 채워지며 버킷은 5개 이상을 보유할 수 없습니다. 버킷이 비어 있으면 요청이 거부됩니다.

class TokenBucket:
    def __init__(self, capacity, refill_per_sec):
        self.capacity = capacity
        self.rate = refill_per_sec
        self.tokens = capacity
        self.last = 0.0

    def allow(self, now):
        elapsed = now - self.last
        self.tokens = min(self.capacity, self.tokens + elapsed * self.rate)
        self.last = now
        if self.tokens >= 1:
            self.tokens -= 1
            return True
        return False

한 번에 7개의 요청을 보냈고 나중에 더 많이 보냈습니다.

burst of 7 at t=0:  [True, True, True, True, True, False, False]
t=2.0:              [True, True, False]
t=10:               5 allowed of 10

처음 5개는 폭발적으로 진행된 다음 버킷이 비어 있었습니다. 2초 후 2개의 토큰이 다시 채워졌으므로 2개의 요청이 더 통과되었습니다. 오랜 시간이 지난 후 버킷이 다시 가득 찼지만 최대 5개로 제한되었습니다. 이러한 버스트 이후 꾸준한 동작은 실제 트래픽에 적합하므로 API 게이트웨이에서 토큰 버킷이 일반적입니다. 누출 버킷은 고정 속도로 요청을 처리하여 버스트를 허용하는 대신 출력을 평활화하는 가까운 친척입니다.

고정창 vs 슬라이딩창

고정 창 카운터는 가장 간단한 접근 방식입니다. 즉, 분당 10개의 요청을 허용하고 분이 변경되면 카운터를 재설정합니다. 경계에 알려진 결함이 있습니다. 59.9초에 10개의 요청을 보냈고 60.0초에 10개의 요청을 더 보냈으며 60초당 10개의 요청으로 제한됩니다.

fixed window allowed around boundary: 20 of 20
sliding log allowed around boundary:  10 of 20

고정 창은 10분의 1초 안에 20개의 요청을 모두 허용했는데, 이는 두 개의 서로 다른 창에 속했기 때문에 의도한 속도의 두 배였습니다. 슬라이딩 로그는 각 최근 요청 시간을 기억하고 지난 60초 동안의 요청 시간을 계산하므로 10초만 올바르게 허용됩니다.

트레이드 오프는 메모리입니다. 슬라이딩 로그는 요청당 타임스탬프를 저장합니다. 미닫이창 카운터는 인기 있는 중간 지점입니다. 적은 메모리를 사용하여 높은 정확도로 현재 창 수와 이전 창 수를 혼합하여 속도를 추정합니다.

알고리즘 비교

알고리즘 버스트 정확도 메모리
고정창 경계에서 최대 2배 낮음 매우 낮음
슬라이딩 로그 아니요 정확함 높음
슬라이딩 윈도우 카운터 작은 좋음 낮음
토큰 버킷 용량까지 허용됨 좋음 낮음
새는 양동이 부드럽게 처리됨 좋음 낮음

무엇으로 제한해야 할까요?

  • API 키 또는 사용자 ID: 인증된 API에 대한 가장 공정한 옵션입니다.
  • IP 주소: 공개 엔드포인트에 유용하지만 많은 사용자가 하나의 IP를 공유할 수 있으며 공격자가 이를 순환할 수 있습니다.
  • 엔드포인트: 검색, 내보내기 또는 로그인과 같은 비용이 많이 드는 작업에는 더 엄격한 제한이 필요합니다.
  • 요금제 등급: 무료 고객과 유료 고객에게는 종종 다른 한도가 적용됩니다.

로그인 엔드포인트에는 특별한 주의가 필요합니다. 계정과 IP로 제한하므로 공격자가 단순히 여러 IP나 여러 ​​계정에 추측을 퍼뜨릴 수 없습니다.

429 응답

클라이언트가 한도를 초과하면 500이나 403이 아닌 HTTP 429 요청이 너무 많음을 반환합니다. 클라이언트에게 무슨 일이 일어났는지, 언제 다시 시도할지 알려주는 헤더를 포함하세요. 우리의 시뮬레이션은 남은 요청이 없는 클라이언트를 위해 다음 세트를 생성했습니다.

HTTP/1.1 429 Too Many Requests
RateLimit-Limit: 100
RateLimit-Remaining: 0
RateLimit-Reset: 30
Retry-After: 30

Retry-After은 표준 HTTP 헤더입니다. RateLimit-* 헤더는 IETF 초안에서 왔으며 많은 API는 자체 X-RateLimit-* 변형을 사용합니다. 무엇을 선택하든 문서로 기록하세요. 상태 코드에 대한 자세한 내용은 HTTP 상태 코드 치트 시트를 참조하세요.

클라이언트로서 한도 처리

429가 발생한 후 즉시 다시 시도하면 상황이 더욱 악화됩니다. 수천 명의 클라이언트가 동시에 이를 수행하면 동기화된 파동으로 서버에 도달합니다. 해결 방법은 지터가 있는 지수 백오프입니다. 각 실패 후 더 오래 기다리고 무작위성을 추가합니다.

def backoff(attempt, base=0.5, cap=30, rng=random.Random(4)):
    return round(min(cap, base * 2 ** attempt) * rng.random(), 2)

[backoff(a) for a in range(6)]
# [0.12, 0.1, 0.79, 0.62, 0.53, 6.43]

이것이 “완전 지터”입니다. 즉, 0과 기하급수적으로 증가하는 한도 사이의 무작위 대기입니다. 대기 시간이 불규칙해 보이는데 그게 바로 핵심입니다. 클라이언트는 함께 재시도하는 대신 분산됩니다. 출력이 재현될 수 있도록 랜덤 생성기를 시드했습니다.

클라이언트 체크리스트: Retry-After 존재하는 경우 재시도 횟수를 제한하고, 반복해도 안전한 재시도 요청만 허용하며, 제한에 도달하기 전에 속도를 늦출 수 있도록 남은 요청 헤더를 확인합니다.

분산 속도 제한

로드 밸런서 뒤에 있는 여러 API 서버가 있는 각 서버는 자체적으로 계산되므로 클라이언트는 요청을 서버 전체에 분산시켜 제한을 초과할 수 있습니다. 팀은 일반적으로 두 서버가 모두 마지막 토큰을 가져갈 수 없도록 원자성 작업이나 짧은 스크립트를 사용하여 Redis와 같은 공유 저장소에 카운터를 보관합니다. Kong, NGINX, Envoy 및 클라우드 API 게이트웨이와 같은 게이트웨이는 이를 구성으로 제공합니다. 이 기사에서는 분산 설정을 실행하지 않았습니다.

테스트 비율 제한

  • 한도까지 요청을 보내고 성공했는지 확인합니다.
  • 하나 더 보내고 올바른 헤더가 포함된 429를 확인하세요.
  • 재설정 시간을 기다린 후 요청이 다시 성공하는지 확인하세요.
  • 키당 제한을 확인하세요. 한 클라이언트의 사용이 다른 클라이언트를 차단해서는 안 됩니다.
  • 이중 버스트 문제에 대해 창 사이의 경계를 테스트합니다.
  • 부하 테스트와 스트레스 테스트에서 다룬 로드 도구를 사용하여 동시성이 심한 경우 동작을 확인합니다.

단위 테스트에서는 시뮬레이션이 now에서 수행하는 것처럼 현재 시간을 주입하므로 테스트가 절전 모드로 전환될 필요가 없습니다.

사용자가 감당할 수 있는 한계 설계

숫자를 선택하는 것은 알고리즘을 선택하는 것만큼 중요합니다. 실제 트래픽에서 시작하세요. 합법적인 클라이언트가 분당 얼마나 많은 요청을 하는지 살펴보고 그 이상으로 제한을 설정하세요. 정상적인 사용을 차단하는 제한은 안전이 아닌 지원 티켓을 생성합니다.

  • API 문서에 엔드포인트별, 계획별 한도를 게시하세요.
  • 차단하기 전에 경고합니다. 남은 요청을 표시하는 헤더를 통해 선량하게 작동하는 클라이언트가 스스로 속도를 늦출 수 있습니다.
  • 웹훅, 대량 엔드포인트 또는 대규모 페이지와 같은 무거운 폴링에 대한 대안을 제공합니다.
  • 429 비율을 모니터링합니다. 갑작스러운 상승은 공격, 버그가 있는 클라이언트 릴리스 또는 현재 너무 엄격한 제한을 의미할 수 있습니다.
  • 의도적으로 예외를 허용합니다. 예를 들어 파트너에 대한 제한을 높이고 하드 코딩하지 않고 구성에 기록합니다.

또한 한도를 바로 초과하여 도착하는 요청에 어떤 일이 발생할지 결정합니다. 일부 API는 소수의 추가 요청을 거부하는 대신 잠시 대기열에 넣어 짧은 급증을 완화합니다. 다른 사람들은 분석과 같이 덜 중요한 엔드포인트보다 결제와 같은 필수 엔드포인트에 우선순위를 부여하여 시스템에 압력이 가해질 때 중요한 트래픽이 계속 흐르도록 합니다.

마무리

좋은 속도 제한은 API와 클라이언트 간의 계약입니다. 서버는 일반적으로 토큰 버킷 또는 슬라이딩 윈도우와 같은 공정한 알고리즘을 선택하고 429 및 Retry-After를 통해 해당 한계를 명확하게 설명합니다. 클라이언트는 해당 신호를 존중하고 지터로 물러납니다. API 키당 넉넉한 제한으로 시작하고, 실제 사용량을 관찰하고, 필요한 경우에만 제한을 강화하세요.

자주 묻는 질문

API 속도 제한이란 무엇입니까?

클라이언트가 주어진 시간에 API에 요청할 수 있는 요청 수(예: 분당 100개)에 대한 제한입니다. 한도를 초과하는 요청은 거부되거나 지연됩니다.

HTTP 429는 무엇을 의미하나요?

429 요청이 너무 많음은 클라이언트가 속도 제한을 초과했음을 의미합니다. 응답에는 대기 시간을 알려주는 Retry-After 헤더가 포함되는 경우가 많습니다.

토큰 버킷 알고리즘이란 무엇입니까?

각 요청은 최대 한도까지 일정한 속도로 다시 채워지는 버킷의 토큰을 사용합니다. 평균 속도를 적용하면서 짧은 버스트를 허용합니다.

속도 제한과 조절의 차이점은 무엇입니까?

속도 제한은 일반적으로 한도를 초과하는 요청을 거부합니다. 제한을 적용하면 속도가 느려지거나 대기열에 추가되는 경우가 많습니다. 용어는 종종 같은 의미로 사용됩니다.

클라이언트는 속도 제한을 어떻게 처리해야 합니까?

재시도 후를 존중하고, 지수 백오프 및 지터로 재시도하고, 재시도 횟수를 제한하고, 남은 요청이 부족하면 속도를 늦춥니다.

계속 학습하세요

Stack Quora와 작업

테스트, WordPress 또는 SEO에 도움이 필요하십니까?

우리는 팀이 더 나은 소프트웨어를 출시하고 사이트를 성장시킬 수 있도록 돕습니다. 현재 진행 중인 작업을 알려주시면 명확한 다음 단계를 제안해 드리겠습니다.

계속 읽으세요

추가 가이드 테스트, AI 및 최신 개발

이 기사가 마음에 드셨나요? 주제를 선택하고 최신 튜토리얼로 바로 이동하세요.

인공지능

AI 환각 설명: 언어 모델이 사물을 구성하는 이유와 이를 줄이는 방법

AI 환각은 그것이 무엇인지, 언어 모델이 환각을 생성하는 이유, 일반적인 유형, 접지 및 프롬프트를 통해 환각을 줄이는 방법, 그리고 우리가 실행한 간단한 점검에 대해 설명했습니다.

기사 읽기 →
DevOps

환경 변수 설명: .env 파일, 비밀 및 구성이 올바르게 완료되었습니다.

우리가 실행한 Python 예제를 통해 설명된 환경 변수: 읽기 및 설정, 모든 값이 문자열인 이유, .env 파일, 프로세스 상속, 비밀 및 유효성 검사.

기사 읽기 →
소프트웨어 개발

API 속도 제한 설명: 알고리즘, 헤더 및 429 오류 처리

우리가 실행한 시뮬레이션을 통해 설명된 API 속도 제한: 토큰 버킷, 고정 창, 슬라이딩 창, 429 응답, 속도 제한 헤더, 백오프를 사용한 재시도 및 테스트 제한.

기사 읽기 →
테스트 자동화

Python에서 조롱: unittest.mock, 패치 및 테스트를 거짓말로 만드는 실수

Unittest.mock을 사용하여 Python에서 모의, 테스트됨: 모의 및 return_value, 부작용, 이름이 사용되는 패치, 사양 및 자동 사양, 모의 날짜 및 일반적인 실수.

기사 읽기 →
소프트웨어 테스트

코드 커버리지 설명: 회선 커버리지와 분기 커버리지 및 100%의 실제 의미

실제 Coverage.py 실행을 통해 설명되는 코드 적용 범위: 라인, 분기 및 조건 적용 범위, 보고서 읽기, 100% 적용 범위가 여전히 버그를 놓칠 수 있는 이유 및 합리적인 대상.

기사 읽기 →
데이터베이스 및 SQL

SQL의 DELETE vs TRUNCATE vs DROP: 차이점, 롤백 및 사용 시기

테스트된 SQL을 통해 DELETE 대 TRUNCATE 대 DROP에 대해 설명합니다. 각각의 제거, 롤백, 트리거, ID 재설정, 속도 및 PostgreSQL, MySQL, SQL Server 및 SQLite의 차이점.

기사 읽기 →
데이터베이스 및 SQL

SQL 뷰 설명: 예제를 통해 함정 생성, 사용 및 방지

우리가 실행한 쿼리로 설명된 SQL 뷰: 뷰 생성, 실시간 결과, 열 숨기기, 성능, 업데이트 가능하고 구체화된 뷰, 손상된 종속성 및 모범 사례.

기사 읽기 →
소프트웨어 개발

TypeScript 인터페이스와 유형: 실제 차이점, 컴파일러로 테스트

TypeScript 인터페이스 대 유형, 실제 컴파일러로 확인: 둘 다 할 수 있는 것, 하나만 할 수 있는 것, 선언 병합, 확장 대 교차점 및 따라야 할 간단한 규칙.

기사 읽기 →
소프트웨어 개발

Python *args 및 **kwargs 설명: 명확한 예가 포함된 유연한 함수

Python *args 및 **kwargs는 우리가 실행한 코드(패킹 및 언패킹, 매개변수 순서, 키워드 전용 및 위치 전용 인수, 데코레이터 및 일반적인 오류)를 설명했습니다.

기사 읽기 →
소프트웨어 개발

Python Lambda 함수: 구문, 실제 사용 및 사용하지 말아야 할 경우

Python 람다 함수는 구문, 키를 사용한 정렬, 맵 및 필터, 클로저, 후기 바인딩 트랩, 일반 def가 더 나은 선택인 경우 등 우리가 실행한 코드로 설명되었습니다.

기사 읽기 →
인공지능

AI 에이전트란 ​​무엇입니까? 작동 방식, 간단한 에이전트 루프를 사용하여 실행할 수 있음

AI 에이전트란 무엇입니까? 우리가 실행한 작은 Python 루프, 실제 위험 및 간단한 챗봇이 더 나은 선택일 때 에이전트 루프, 도구, 메모리 및 가드레일에 대한 일반 가이드입니다.

기사 읽기 →
DevOps

모니터링과 관찰 가능성: 로그, 지표, 추적을 통한 실제 차이점

모니터링과 관찰 가능성 설명: 알려진 오류와 알려지지 않은 오류, 로그, 지표 및 추적, 결제 사건 안내, 골든 신호, OpenTelemetry 및 유용한 경고.

기사 읽기 →
DevOps

Docker 볼륨과 바인딩 마운트: 컨테이너 데이터를 올바른 방식으로 유지

Docker 볼륨과 바인드 마운트 설명: 컨테이너 데이터가 사라지는 이유, 명명된 볼륨, 바인드 마운트, tmpfs, Compose 예제, 백업, 권한 및 각 사용 시기.

기사 읽기 →
테스트 자동화

TDD와 BDD: 주요 차이점, 두 가지 방식으로 구축된 하나의 기능 및 각 사용 시기

TDD와 BDD는 두 가지 방식으로 구축된 하나의 할인 기능, 즉 우리가 실행한 코드를 사용한 적록 리팩토링, 주어진 시점 시나리오, 도구, 장단점 및 각 사용 시기를 설명합니다.

기사 읽기 →
소프트웨어 개발

Git merge vs rebase: 차이점, 예제, 언제 무엇을 쓸까

Git merge vs rebase를 실제 로그 출력, 비교표, rebase의 황금률, 안전한 팀 워크플로로 설명합니다.

기사 읽기 →
소프트웨어 개발

파이썬 리스트 컴프리헨션: 문법, 예제, 피해야 할 때

파이썬 리스트 컴프리헨션 설명: 문법, 필터링, if-else, 중첩 반복문, 실제 측정 시간, 그리고 일반 for 반복문이 더 나은 경우.

기사 읽기 →
데이터베이스 및 SQL

예제로 쉽게 배우는 SQL JOIN (Inner, Left, Right, Full)

샘플 테이블과 쿼리로 SQL JOIN을 단계별로 이해하세요. INNER, LEFT, RIGHT, FULL, CROSS, SELF와 흔한 실수, 성능 팁까지 정리했습니다.

기사 읽기 →