사전 RateLimit 헤더 필드
표준

RateLimit 헤더 필드

gabury1고친 사람 github-actions[bot]

RateLimit 헤더 필드는 서버가 요청 한도가 얼마나 남았는지 응답마다 알려 주는 헤더입니다. 클라이언트는 이 값을 보고 한도에 닿기 전에 스스로 요청을 늦춥니다. 서비스마다 제각각이던 한도 헤더를 하나로 맞추려고 표준 단체가 다듬고 있는 초안입니다.

쉽고 빠른 이해

RateLimit 헤더 필드는 응답에 남은 요청 한도를 적어 보내는 헤더입니다. 서버가 RateLimit: "default";r=50;t=30 을 붙여 보냈다고 합시다. "default" 는 서버가 건 규칙의 이름입니다. 그 규칙으로 50번이 남았습니다. 앞으로 30초 동안은 그보다 많이 보낼 수 없습니다.

이게 없으면 클라이언트는 거절 응답(429)을 받고 나서야 한도를 넘은 줄 압니다. 서비스마다 헤더 이름과 값의 뜻도 달라서 읽는 코드를 서비스마다 따로 짜야 했습니다.

  1. 서버가 RateLimit-Policy 에 규칙을 적습니다. 몇 초 동안 몇 번까지인지입니다
  2. 응답마다 RateLimit 에 지금 남은 횟수와 남은 초를 적습니다
  3. 클라이언트는 남은 횟수가 바닥나면 남은 초가 지나기를 기다렸다가 보냅니다

외부 개발자에게 여는 서비스처럼 속도 제한을 거는 곳에서 씁니다. 대가는 서버가 요청 수를 늘 세어 두고 응답마다 적어야 한다는 것입니다. 아직 초안이라 판이 올라갈 때마다 필드 모양도 바뀌어 왔습니다.

상세

속도 제한은 한 클라이언트가 정해진 시간 동안 보낼 수 있는 요청 수를 서버가 묶어 두는 일입니다. 「1분에 100번」처럼 정합니다. 한도를 넘은 요청은 HTTP 429(Too Many Requests) 응답으로 거절됩니다.

헤더는 HTTP(HyperText Transfer Protocol, 하이퍼텍스트 전송 프로토콜) 메시지의 본문 앞에 붙어 부가 정보를 적는 이름: 값 꼴의 줄입니다. Content-Type: application/json 이 그 예입니다.

RateLimit 헤더 필드는 속도 제한의 상태를 응답에 실어 보내는 헤더입니다. 이 필드는 거절 응답뿐 아니라 성공 응답에도 붙습니다. 클라이언트는 거절을 받기 전에 남은 한도를 알 수 있습니다.

이 필드는 아직 인터넷 드래프트입니다. 인터넷 드래프트는 표준으로 굳히기 전에 다듬는 초안 문서입니다. 초안은 판을 올려 가며 고칩니다. 이 필드는 지금 11판까지 나왔습니다.

표준으로 굳은 문서는 RFC(Request for Comments)라는 번호를 받습니다. 이 필드는 아직 RFC 번호가 없습니다.

뜻이 제각각이던 X-RateLimit 헤더

초안이 나오기 전에도 많은 서비스가 한도 상태를 헤더에 실어 보냈습니다. 이름 앞에는 X- 를 붙였습니다. 표준에 없는 헤더라는 표시로 쓰던 관례입니다.

가장 흔한 이름은 셋이었습니다. 셋 다 한도 하나의 상태를 나눠 담습니다.

이름 담는 값
X-RateLimit-Limit 한 기간에 허용하는 요청 수
X-RateLimit-Remaining 이번 기간에 남은 요청 수
X-RateLimit-Reset 기간이 언제 끝나는지

문제는 이름이 같아도 값의 뜻이 서비스마다 갈렸다는 것입니다. X-RateLimit-Reset 이 특히 그랬습니다. 어떤 서비스는 남은 초를 적었습니다. 어떤 서비스는 끝나는 시각을 유닉스 시간으로 적었습니다. 유닉스 시간은 협정 세계시로 1970년 1월 1일 0시부터 센 초입니다.

http
X-RateLimit-Reset: 60
X-RateLimit-Reset: 1758790860

위 두 줄은 이름이 같습니다. 앞 줄은 60초 뒤를, 뒤 줄은 특정 시각을 가리킵니다. 받는 쪽은 값만 보고 둘을 가를 수 없습니다. 밀리초로 적는 곳도 있었습니다. x-ratelimit-limit-minute 처럼 기간을 이름에 넣는 곳도 있었습니다.

클라이언트는 서비스마다 읽는 코드를 따로 가져야 했습니다. RateLimit 헤더 필드는 이름과 값의 뜻을 하나로 맞추려고 나왔습니다.

규칙과 현재 상태를 나눈 두 필드

지금 판은 필드를 둘로 나눕니다. 하나는 서버가 건 규칙입니다. 다른 하나는 지금 남은 양입니다.

필드 담는 것 바뀌는 빈도
RateLimit-Policy 몇 초 동안 몇 번까지인지 거의 안 바뀝니다
RateLimit 지금 얼마나 남았고 몇 초 동안 쓸 수 있는지 응답마다 바뀝니다

둘을 나눈 까닭은 바뀌는 빈도가 달라서입니다. 규칙은 한 번 알면 됩니다. 남은 양은 매번 새로 알아야 합니다.

서버가 건 규칙 하나를 정책이라고 부릅니다. 정책마다 앞에 이름이 붙습니다(예: "default"). 두 필드는 이 정책 이름으로 서로를 가리킵니다.

응답에 두 필드가 함께 붙으면 이렇게 보입니다.

http
HTTP/1.1 200 OK
RateLimit-Policy: "default";q=100;w=60
RateLimit: "default";r=50;t=30

"default" 정책의 규칙은 q=100;w=60 입니다. 60초(w)에 100번(q)까지 허용합니다. 지금 상태는 r=50;t=30 입니다. 남은 한도(r)는 50번입니다. 앞으로 30초(t) 동안은 50번을 넘겨 보낼 수 없습니다.

값을 적는 문법

두 필드의 값은 구조화 필드(Structured Fields)라는 문법을 따릅니다. 구조화 필드는 HTTP 가 헤더 값을 적는 공통 문법입니다. 이 문법이 있으면 새 헤더를 만들 때마다 읽는 규칙을 새로 짤 필요가 없습니다. 이미 있는 파서로 읽으면 됩니다.

이 문서의 예시를 읽는 데는 표기 넷이면 됩니다.

표기 뜻 예
큰따옴표 문자열. 여기서는 정책 이름 "default"
;키=값 앞 항목에 붙는 파라미터 ;q=100
쉼표 목록의 다음 항목 "burst";q=100,"daily";q=1000
콜론 두 개 사이 바이트열. Base64 로 적습니다 :cHsdsRa894==:

Base64 는 바이트를 영문자와 숫자로 바꿔 적는 방법입니다. 헤더에는 글자만 실을 수 있어서 바이트를 이렇게 옮겨 적습니다.

RateLimit-Policy 의 파라미터

RateLimit-Policy 는 정책을 하나 이상 적습니다. 정책마다 이름을 앞에 두고 파라미터를 붙입니다. q 는 한도를 뜻하는 영어 quota(쿼터)의 머리글자입니다.

파라미터 뜻 필수
q 이 정책이 허용하는 한도 필수
w 한도를 세는 기간. 초 단위 선택
qu 한도를 세는 단위. 없으면 요청 수 선택
pk 이 요청이 속한 파티션 키. 아래 소절 선택

쉼표로 정책을 여럿 걸 수도 있습니다. 짧은 기간과 긴 기간을 함께 거는 경우가 그렇습니다.

http
RateLimit-Policy: "burst";q=100;w=60,"daily";q=1000;w=86400

"burst" 는 1분에 100번, "daily" 는 하루(86400초)에 1000번입니다. 짧은 기간은 한꺼번에 몰리는 요청을 막습니다. 긴 기간은 하루 총량을 막습니다.

qu 로 무엇을 셀지도 바꿀 수 있습니다. 세 값이 있습니다.

qu 값 세는 것
requests 처리한 요청 수. 기본값
content-bytes 처리한 본문 바이트 수
concurrent-requests 동시에 처리 중인 요청 수

RateLimit 의 파라미터

RateLimit 은 정책 이름을 앞에 두고 지금 상태를 붙입니다.

파라미터 뜻 필수
r 그 정책으로 지금 남은 한도 필수
t 남은 한도를 쓸 수 있는 남은 시간. 초 단위 선택
pk 이 요청이 속한 파티션 키 선택

t 가 가리키는 기간을 유효 창(effective window)이라고 부릅니다. 앞 소절 예시에서는 t=30 이니 앞으로 30초가 유효 창입니다.

파티션 키

서버는 한도를 누구 단위로 셀지 정합니다. 사용자마다 셀 수 있습니다. 애플리케이션이나 HTTP 메서드, 자원마다 셀 수도 있습니다. 이것들을 섞기도 합니다.

파티션 키는 이 요청이 어느 묶음으로 세어졌는지 가리키는 값입니다. 사용자 둘이 같은 정책을 쓰더라도 남은 한도는 따로입니다. 서버는 응답에 파티션 키를 실어 어느 묶음의 숫자인지 밝힙니다.

http
RateLimit-Policy: "peruser";q=100;w=60;pk=:cHsdsRa894==:

값은 바이트열이라 클라이언트가 풀어 읽는 것이 아닙니다. 서버가 붙인 표식으로 둡니다. 클라이언트는 같은지 다른지만 봅니다.

한 번 주고받는 모습

아래는 한도가 두 번 남은 클라이언트가 요청을 이어 보내는 모습입니다. 성공 응답마다 남은 한도가 줄어드는 것을 봅니다.

sequenceDiagram
    participant 클라이언트
    participant 서버
    클라이언트->>서버: GET /items
    서버-->>클라이언트: 200 · RateLimit r=1 t=20
    클라이언트->>서버: GET /items
    서버-->>클라이언트: 200 · RateLimit r=0 t=19
    Note over 클라이언트: r 이 0 이라 19초를 기다린다
    클라이언트->>서버: 19초 뒤 GET /items
    서버-->>클라이언트: 200 · 새 RateLimit 값

두 번째 응답에서 남은 한도가 0 이 되었습니다. 클라이언트는 세 번째 요청을 바로 보내지 않고 유효 창이 지나기를 기다립니다. 이 필드가 없었다면 세 번째 요청은 429 로 거절되었을 겁니다.

남은 한도를 읽는 규칙

이 필드의 값은 약속이 아니라 안내입니다. 클라이언트가 이 값을 어디까지 믿어도 되는지는 아래 규칙들이 정합니다.

규칙 끝 괄호의 영어 낱말은 요구 강도입니다. 이 낱말들은 RFC 2119 가 정했습니다.

낱말 뜻
MUST · MUST NOT 반드시 지켜야 합니다
SHOULD · SHOULD NOT 까닭이 있으면 어겨도 됩니다
MAY 해도 되고 안 해도 됩니다

클라이언트는 남은 한도가 양수라고 다음 요청이 처리된다고 가정해서는 안 됩니다(MUST NOT). 남은 한도가 적다는 것은 서버가 곧 이 클라이언트를 조일 수 있다는 신호입니다. r 이 줄어들면 바닥나기 전에 요청 속도를 늦추는 것이 이 필드의 쓰임입니다.

클라이언트는 유효 창이 지나면 한도가 전부 되살아난다고 가정해서도 안 됩니다(MUST NOT). 서버는 요청과 요청 사이에 남은 한도와 유효 창을 바꿀 수 있습니다(MAY). 부하가 몰리면 서버가 한도를 줄이는 식입니다.

Retry-After 와 함께 올 때

Retry-After 는 몇 초 뒤에 다시 보내라고 알리는 기존 HTTP 헤더입니다. 거절 응답에는 이 헤더와 RateLimit 이 함께 올 수 있습니다.

둘이 함께 오면 클라이언트는 Retry-After 를 따릅니다(MUST). 그때 클라이언트는 유효 창을 무시해도 됩니다(MAY).

서버에도 규칙이 하나 붙습니다. 서버는 Retry-After 를 유효 창이 끝나기보다 이른 시점으로 적지 않아야 합니다(SHOULD NOT). 두 헤더가 서로 다른 말을 하지 않게 하려는 규칙입니다.

클라이언트가 다음 요청을 언제 보낼지 가르는 순서를 그리면 이렇습니다.

flowchart TD
    A{"Retry-After 가 있나"} -- 있음 --> B["그 시간이 지나기를 기다린다"]
    A -- 없음 --> C{"RateLimit 의 r 가 0 인가"}
    C -- 예 --> D["t 초가 지나기를 기다린다"]
    C -- 아니오 --> E["보낸다 · r 이 적으면 속도를 늦춘다"]

06판의 네 필드

이 초안은 판이 올라가며 필드 모양을 바꿔 왔습니다. 2022년 12월의 06판은 필드를 넷으로 나눠 적었습니다. 지금 판은 이것을 두 필드로 합쳤습니다.

http
RateLimit-Limit: 100
RateLimit-Remaining: 50
RateLimit-Reset: 50
RateLimit-Policy: 100;w=60

06판은 이름에서 X- 를 뗐습니다. 값의 뜻도 하나로 정했습니다. RateLimit-Reset 은 끝나는 시각이 아니라 남은 초입니다. 11판은 여기에 더해 정책에 이름을 붙입니다. 남은 한도도 그 이름에 묶어 적습니다.

알리는 것 06판 11판
기간당 한도 RateLimit-Limit RateLimit-Policy 의 q
남은 한도 RateLimit-Remaining RateLimit 의 r
남은 시간 RateLimit-Reset RateLimit 의 t
정책 RateLimit-Policy · 이름 없음 RateLimit-Policy · 이름 붙음

앞 판을 따라 만든 서버는 앞 판의 이름을 보냅니다. 받는 쪽은 어느 판인지부터 가려야 합니다. RateLimit-Limit · RateLimit-Remaining · RateLimit-Reset 은 06판에만 있는 이름입니다. 이 셋이 오면 06판입니다.

RateLimit-Policy 는 두 판에 이름이 같아서 값의 모양으로 가립니다. 값이 "default";q=100 처럼 정책 이름으로 시작하면 11판입니다. 100;w=60 처럼 숫자로 시작하면 06판입니다. 초안이 RFC 로 굳기 전까지는 모양이 또 바뀔 수 있습니다.

붙이는 서비스와 서버가 지는 부담

이 필드는 속도 제한을 거는 서비스에서만 뜻이 있습니다. API(Application Programming Interface)는 프로그램끼리 서로 부르는 창구입니다. 외부 개발자에게 여는 API 처럼 서버가 클라이언트 코드를 고칠 수 없는 경우에 이 필드의 쓸모가 큽니다. 클라이언트가 한도를 보고 스스로 늦춰 주기를 바랄 수밖에 없기 때문입니다.

응답마다 남은 한도를 적으려면 서버는 요청을 받을 때마다 셈을 고치고 바로 읽을 수 있어야 합니다. 서버를 여러 대 두면 셈을 한곳에 모아야 숫자가 맞습니다. 각자 따로 세면 같은 사용자에게 서버마다 다른 남은 한도를 알리게 됩니다.

관련 항목

이 필드를 정의하는 표준·문서

인터넷 드래프트 · IETF · RFC · RFC 9110 · RFC 2119 · 구조화 필드 · Base64

이 필드와 함께 실리는 상태 코드와 헤더

HTTP 429 · Retry-After · 상태 코드 · HTTP 응답 · 503 Service Unavailable

이 필드가 알리는 한도의 구성 요소

쿼터 · 쿼터 정책 · 서비스 한도 · 파티션 키 · 유효 창 · 버스트

이 필드가 대신하려는 비표준 헤더

X-RateLimit-Limit · X-RateLimit-Remaining · X-RateLimit-Reset · X- 접두사 · 유닉스 시간

서버가 한도를 세는 알고리즘

토큰 버킷 · 리키 버킷 · 고정 윈도우 · 슬라이딩 윈도우 로그 · 슬라이딩 윈도 카운터

이 신호를 받아 요청을 늦추는 클라이언트 기법

재시도 · 지수 백오프 · 지터 · 재시도 폭풍 · 백프레셔

이 필드를 내보내는 서버 구성 요소

API 게이트웨이 · 리버스 프록시 · 속도 제한 · 스로틀링

이것이 속하는 상위 분류

HTTP · API 설계 · HTTP API · 헤더

다른 이름: RateLimit · RateLimit-Policy · RateLimit header fields · RateLimit 헤더 · 레이트 리밋 헤더