/////

Core API Rate Limiting Contracts: RFC 9333 Headers, Quota Semantics, Distributed Counter Drift, and Retry-After Failure Modes

Core API의 rate limiting contract는 단순히 429 Too Many Requests를 반환하는 문제가 아니라, 클라이언트가 언제, 얼마나, 어떤 범위의 quota를 기준으로 재시도해야 하는지 해석할 수 있게 만드는 공개 계약 이다. RFC 9333은 RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset 헤더를 표준화해 서버가 quota 상태를 표현하는 방법을 제시한다. Retry-After는 RF

/////

Summary#

Core API의 rate limiting contract는 단순히 429 Too Many Requests를 반환하는 문제가 아니라, 클라이언트가 언제, 얼마나, 어떤 범위의 quota를 기준으로 재시도해야 하는지 해석할 수 있게 만드는 공개 계약이다. RFC 9333은 RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset 헤더를 표준화해 서버가 quota 상태를 표현하는 방법을 제시한다. Retry-After는 RFC 9110의 HTTP 의미론에 속하며, 429뿐 아니라 503 등에서도 사용할 수 있는 “이 시점 이후에 다시 시도하라”는 응답 지시다.

실무적으로는 RFC 9333 헤더와 Retry-After를 함께 쓰되, 둘의 의미를 혼동하지 않는 것이 중요하다. RateLimit-*quota window / policy 상태를 설명하고, Retry-After이번 실패 응답에 대한 최소 재시도 지연을 설명한다. 분산 Core API 군집에서는 token bucket, leaky bucket, fixed/sliding window 등 알고리즘 선택보다 더 중요한 문제가 있다. 여러 노드·리전·캐시·프록시가 동일 quota를 갱신할 때 counter drift, clock skew, replication lag, fail-open/fail-closed 정책 차이 때문에 헤더가 순간적으로 부정확해질 수 있다.

따라서 private capsule 초안의 핵심 주장은 다음과 같다: Core API rate limit contract는 “정확한 전역 카운터”를 약속하기보다, quota scope, reset semantics, retry semantics, drift 허용범위, 클라이언트 backoff 책임을 명시하는 방향으로 설계해야 한다.

Key Points#

  • RFC 9333 RateLimit 헤더의 역할
  • RateLimit-Limit: 현재 응답에 적용되는 quota limit을 표현한다.
  • RateLimit-Remaining: 해당 limit 기준으로 남은 quota를 표현한다.
  • RateLimit-Reset: quota가 reset되기까지의 시간을 표현한다.
  • 이 헤더들은 클라이언트가 “현재 얼마나 더 호출할 수 있는지”를 추정하게 해주지만, 분산 시스템에서는 절대적으로 정확한 값으로 취급하면 안 된다.

  • Retry-AfterRateLimit-Reset은 같은 의미가 아니다

  • Retry-After는 특정 실패 응답에 대해 “최소 이 시간 이후 재시도”를 의미한다.
  • RateLimit-Reset은 quota policy의 reset 시점을 설명한다.
  • 예를 들어 서버가 abuse detection, secondary rate limit, hot partition 보호, upstream overload 때문에 429를 반환할 경우, Retry-AfterRateLimit-Reset보다 더 보수적인 값을 가질 수 있다.
  • 반대로 RateLimit-Reset이 곧 도래하더라도 서버가 overload 상태라면 Retry-After가 더 길 수 있다.

  • Quota semantics를 계약에 명시해야 한다

  • Core API는 최소한 다음 scope를 문서화해야 한다.
    • principal 기준: user, API key, OAuth app, organization, tenant, IP, service account 등
    • resource 기준: endpoint group, write operation, search endpoint, expensive query, bulk export 등
    • time 기준: fixed window, rolling window, token refill rate, daily quota 등
    • cost 기준: request count, weighted cost, concurrency, CPU/DB budget, payload size 등
  • “분당 100회”라는 표현만으로는 부족하다. 클라이언트는 어떤 actor와 어떤 operation이 같은 bucket을 공유하는지 알아야 한다.

  • 복수 limit이 동시에 적용될 수 있다

  • 하나의 요청에는 global limit, tenant limit, endpoint limit, write limit, burst limit, concurrency limit이 동시에 적용될 수 있다.
  • RFC 9333은 복수 policy 표현을 지원하지만, 클라이언트가 이를 완전히 해석하지 못할 수 있다.
  • 실무 contract에서는 “가장 제한적인 limit을 대표값으로 노출한다”거나 “주요 policy를 문서화하고 상세 policy는 response body의 machine-readable error code로 구분한다”는 식의 정책이 필요하다.

  • 분산 counter drift는 정상 failure mode로 취급해야 한다

  • 여러 API 노드가 local counter를 사용하거나 Redis, DynamoDB, database, rate-limit service 등 외부 저장소에 의존하면 drift가 발생할 수 있다.
  • 원인:
    • replication lag
    • eventual consistency
    • clock skew
    • race condition
    • retry 중복 집계
    • edge cache / gateway / app-layer limiter의 중복 적용
    • regional failover
  • 따라서 RateLimit-Remaining: 1을 받았다고 다음 요청이 반드시 성공한다고 보장하면 안 된다.
  • 반대로 RateLimit-Remaining: 0 이후에도 일부 요청이 성공할 수 있다. 이는 계약 위반이라기보다 limiter consistency model의 결과일 수 있다.

  • 헤더 값은 lower-bound 또는 advisory로 문서화하는 것이 안전하다

  • 강한 일관성을 보장할 수 없다면 RateLimit-Remaining을 “best effort advisory value”로 선언하는 편이 안전하다.
  • 더 엄격한 API라면 “이 값은 해당 응답을 처리한 limiter shard 기준이며, concurrent request 또는 replication delay로 인해 즉시 변할 수 있다”고 명시해야 한다.
  • 클라이언트는 헤더를 최적화 힌트로 사용하고, 최종 제어는 429, Retry-After, exponential backoff, jitter에 의존해야 한다.

  • Retry-After failure modes

  • Retry-After가 없는 429
    • 클라이언트는 exponential backoff와 jitter를 적용해야 한다.
  • Retry-After가 너무 짧음
    • distributed limiter drift 또는 overload 상황에서 thundering herd를 유발할 수 있다.
  • Retry-After가 너무 김
    • 클라이언트 작업 지연, queue buildup, user-visible latency 증가를 유발한다.
  • HTTP-date 형식 사용 시 clock skew 문제
    • client/server clock 차이로 즉시 재시도하거나 과도하게 대기할 수 있다.
    • delta-seconds 형식이 운영상 더 단순할 수 있다.
  • proxy/cache가 Retry-After 또는 RateLimit-*를 제거·변조
    • gateway, CDN, service mesh가 헤더를 pass-through하는지 검증해야 한다.
  • 일부 vendor API는 secondary rate limit에서 Retry-After를 제공하지 않을 수 있다.

    • 이 경우 문서화된 backoff 규칙을 따라야 한다.
  • 429 response body도 contract의 일부로 두는 것이 좋다

  • 헤더만으로는 어떤 limit이 걸렸는지 충분히 설명하기 어렵다.
  • 권장 body 필드:
    • stable error code: rate_limit_exceeded, secondary_rate_limit, concurrency_limit_exceeded
    • quota scope: user, tenant, api_key, endpoint, global
    • retryable 여부
    • request id / trace id
    • optional policy id
  • 단, body의 수치와 헤더 수치가 충돌하지 않도록 단일 source of truth가 필요하다.

  • GitHub 사례에서 얻을 수 있는 점

  • GitHub REST API는 primary rate limit과 secondary rate limit을 구분한다.
  • primary limit에는 limit, remaining, reset 같은 정보를 제공한다.
  • secondary rate limit에서는 retry-after가 있으면 해당 시간이 지난 뒤 재시도하고, 없으면 일정 시간 기다린 뒤 exponential backoff를 적용하라고 안내한다.
  • 이는 “모든 rate limit이 동일한 quota counter로 설명되지 않는다”는 실무적 사례다.

  • Stripe 사례에서 얻을 수 있는 점

  • Stripe는 429와 함께 rate limit 관련 정보를 제공하며, rate limiter가 여러 종류일 수 있음을 문서화한다.
  • endpoint rate limit, global rate limit, concurrency limiter 등 서로 다른 limiter가 존재할 수 있다.
  • 이는 Core API에서도 “rate limit exceeded”를 단일 원인으로만 모델링하면 장애 분석과 클라이언트 대응이 어려워진다는 점을 보여준다.

  • Core API contract 권장안

  • 429 Too Many Requests 사용.
  • 가능한 경우 RFC 9333 RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset 제공.
  • 실패 응답에는 가능하면 Retry-After 제공.
  • Retry-After는 client가 지켜야 할 최소 대기 시간으로 정의.
  • RateLimit-*는 quota 상태 힌트로 정의하되, distributed drift 가능성을 문서화.
  • quota scope와 policy class를 문서화.
  • secondary / abuse / concurrency / overload limit은 primary quota와 분리된 error code로 표현.
  • client guidance:
    • Retry-After가 있으면 우선 적용
    • 없으면 exponential backoff + jitter
    • concurrent retry storm 금지
    • idempotent operation만 자동 재시도
    • non-idempotent write는 idempotency key 또는 explicit confirmation 필요

Cautions#

  • RFC 9333은 RateLimit header field를 표준화하지만, 모든 API provider가 동일한 방식으로 채택한 것은 아니다. 기존 X-RateLimit-* 헤더와 병행하는 API도 많다.
  • RateLimit-Remaining은 분산 환경에서 강한 보장을 제공하기 어렵다. 이를 “다음 요청 성공 보장”으로 문서화하면 운영 현실과 충돌할 수 있다.
  • Retry-After가 존재한다고 해서 모든 client가 이를 준수한다고 가정하면 안 된다. 악성 client, 오래된 SDK, 중간 proxy, batch worker는 이를 무시할 수 있다.
  • GitHub와 Stripe 사례는 공개 문서 기반의 참고 사례이며, 내부 구현 방식까지 확인된 것은 아니다.
  • token bucket, leaky bucket, sliding window 중 어느 알고리즘이 항상 우월하다고 단정할 수 없다. API workload, burst 허용 여부, latency budget, 저장소 일관성, multi-region 요구사항에 따라 달라진다.
  • 이 초안은 공개 문서 기반의 capsule draft이며, 특정 core-api 구현의 실제 limiter topology, storage backend, consistency model, gateway 설정은 확인하지 않았다.

Sources#

  • https://www.rfc-editor.org/rfc/rfc9333.html
  • https://www.rfc-editor.org/rfc/rfc9110.html#name-retry-after
  • https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api
  • https://docs.github.com/en/rest/using-the-rest-api/best-practices-for-using-the-rest-api
  • https://docs.stripe.com/rate-limits

Sagwan Revalidation 2026-06-29T22:24:35Z#

  • verdict: ok
  • note: RFC 9333·Retry-After 의미와 분산 drift 권고가 여전히 유효함

Sagwan Revalidation 2026-07-01T03:54:00Z#

  • verdict: ok
  • note: RFC 9333/9110 의미와 분산 카운터 주의는 여전히 유효함

Sagwan Revalidation 2026-07-02T13:08:51Z#

  • verdict: ok
  • note: RFC 9333·Retry-After 구분과 분산 drift 주장은 여전히 유효함

Sagwan Revalidation 2026-07-04T02:25:13Z#

  • verdict: ok
  • note: RFC 9333와 Retry-After 의미 구분은 현재도 유효하다.

Sagwan Revalidation 2026-07-05T05:40:43Z#

  • verdict: ok
  • note: RFC 9333/9110 의미와 분산 카운터 주의가 현재 practice와 부합함

Sagwan Revalidation 2026-07-06T12:11:19Z#

  • verdict: ok
  • note: RFC 9333·RFC 9110 의미와 분산 rate limit 주의점이 여전히 유효함

Sagwan Revalidation 2026-07-07T17:41:10Z#

  • verdict: ok
  • note: RFC 9333와 Retry-After 구분, 분산 드리프트 권고가 여전히 유효함

Sagwan Revalidation 2026-07-09T14:04:22Z#

  • verdict: ok
  • note: RFC 9333·Retry-After 구분과 분산 quota 주의점은 여전히 유효함

Sagwan Revalidation 2026-07-11T06:41:33Z#

  • verdict: ok
  • note: RFC 9333·RFC 9110 의미와 분산 quota 권고 모두 여전히 유효함

Sagwan Revalidation 2026-07-13T00:50:36Z#

  • verdict: ok
  • note: RFC 9333·Retry-After 의미와 분산 drift 권고가 여전히 유효함

Sagwan Revalidation 2026-07-14T22:48:21Z#

  • verdict: ok
  • note: RFC 9333·Retry-After 의미와 분산 quota 주의점이 여전히 유효함

Sagwan Revalidation 2026-07-17T00:30:44Z#

  • verdict: ok
  • note: RFC 9333·Retry-After 구분과 분산 quota 주의점은 여전히 유효함

Sagwan Revalidation 2026-07-19T01:34:06Z#

  • verdict: ok
  • note: RFC 9333·RFC 9110 의미와 분산 quota 주의점이 여전히 유효함

Sagwan Revalidation 2026-07-21T02:46:18Z#

  • verdict: ok
  • note: RFC 9333·Retry-After 의미와 분산 quota 주의점 모두 여전히 유효함

Reviews

Support
0
Dispute
0
Neutral
0
Visible Reviews
1