방어선: 세 시스템, 하나가 아니라

발행: (2026년 2월 28일 오후 01:50 GMT+9)
15 분 소요
원문: Dev.to

Source: Dev.to

번역할 텍스트를 제공해 주시면 한국어로 번역해 드리겠습니다.

세 가지 메커니즘

“Rate limiting”(속도 제한)은 요청을 거부하거나 지연시키는 모든 상황을 포괄적으로 일컫는 경우가 많습니다. 실제로는 세 가지 구별된 메커니즘이 존재하며, 각각은 다른 장애 유형을 방어하고 다른 질문을 제기합니다.

메커니즘제기하는 질문보호 대상
Load shedding“이 서버가 어떤 요청이든 처리할 만큼 건강한가요?”서버가 자신을 보호한다
Rate limiting“이 호출자가 너무 많은 요청을 보내고 있나요?”시스템이 남용하는 호출자를 보호한다
Adaptive throttling“현재 다운스트림이 어려움을 겪고 있나요?”다운스트림 서비스가 이 서버로부터 보호받는다

서버가 OOM(메모리 초과) 상태일 때 속도 제한기만으로는 구제되지 않습니다 — 모든 사용자는 할당량 내에 있지만 서버는 죽어가고 있습니다.
로드 셰딩만으로는 한 고객이 용량의 80 %를 차지하는 것을 막을 수 없습니다 — 전체 동시성은 괜찮지만 배분이 불공평합니다.
어느 것도 이미 어려움을 겪고 있는 다운스트림 서비스를 과도하게 호출하는 것을 막지 못합니다.

이것들은 보완적인 시스템입니다. 이를 하나의 것으로 취급하거나 세 가지 중 하나만 구현하면, 보호가 가장 필요한 순간에 나타나는 빈틈이 생깁니다.

Layer 1 – Load Shedding

Protects this server from itself.

  • 메모리 압박이 너무 심한가요?
  • 동시 요청이 너무 많은가요?
  • 하위 서비스가 RESOURCE_EXHAUSTED를 반환했나요?

If any of these are true, reject immediately—doesn’t matter who the user is or what the request is. The building is at capacity.

레이어 2 – Rate Limiting

Protects the system from abusive users.

  • Is this specific user, API key, or IP address sending more than its allowed share?

This is the classic rate limiter—per‑user counters, sliding windows, token buckets.

Layer 3 – Adaptive Throttling

이 서버로부터 다운스트림 서비스를 보호합니다.

  • 서버는 각 다운스트림을 호출할 때 성공률을 추적합니다.
  • 결제 서비스에 대한 호출의 20 %가 실패하면, 서버는 확률적으로 아웃바운드 호출의 20 %를 차단하기 시작합니다—결제 서비스가 회복할 수 있도록 여유를 제공합니다.

순서가 중요한 이유

  1. Load shedding이 가장 높은 우선순위로 실행됩니다—인증보다, 요청 파싱보다, 다른 모든 것보다 먼저.
  2. **rate limiting (Layer 2)**이 먼저 실행되면 서버는 CPU를 사용해 Redis 카운터를 확인하고, 슬라이딩‑윈도우 수학을 계산하며, 사용자별 조회를 수행합니다. 그 후에 Layer 1에 도달해 “사실 서버가 죽어가니, 모든 것을 거부한다.”는 메시지를 받게 됩니다. 이 모든 작업이 낭비됩니다.
  3. Load shedding은 비용이 저렴합니다—원자적 카운터 체크 하나 또는 GC‑flag 읽기 하나. 마이크로초 수준입니다. Rate limiting은 Redis 왕복이 필요할 수 있습니다. 저렴한 체크를 먼저 실행하세요.
  4. Analogy – 나이트클럽을 생각해 보세요: 입구의 소방관(Load shedding)은 신분증을 확인하지 않습니다. “건물이 가득 찼다. 아무도 들어올 수 없다.” 건물이 가득 차지 않았을 때만 문지기(rate limiter)가 손님 명단을 확인합니다.

Illustrative Scenarios

상황레이어 1이 하는 일레이어 2가 하는 일레이어 3이 하는 일
배포 오류 – 새로운 ML 모델이 메모리를 3× 사용GC 압력 급증을 감지하고 셰딩을 시작블라인드 – 모든 사용자가 제한 내블라인드 – 하위 서비스는 정상
한 고객이 10× 급증 – 마이그레이션 스크립트 버그전체 동시성이 제한을 초과하면 결국 감지 가능즉시 감지 – 사용자별 카운터가 임계값 초과블라인드 – 하위 서비스는 정상
하위 결제 서비스 성능 저하 – 40 %에서 RESOURCE_EXHAUSTED 반환해당 응답에 대해 반응형 백오프 수행블라인드 – 사용자는 제한 내확률적으로 아웃바운드 호출을 드롭하여 서비스에 여유 제공
DDoS – 수천 개 IP가 각각 중간 정도 트래픽전체 동시성 급증 감지IP당 제한 감지(설정된 경우)블라인드 – 인바운드 문제
느린 의존성 – DB 쿼리가 5 ms에서 2 s로 증가동시 요청 수가 제한에 가까워지는 급증 감지블라인드 – 사용자는 제한 내오류를 감지하지 못할 수 있음(느린 응답은 오류가 아님)
레이어 1과 레이어 2 모두 실패여전히 하위 서비스로의 연쇄 영향을 방지

핵심: 단일 레이어만으로 모든 것을 처리할 수 없습니다. 서로 보완 관계이며 중복되지 않습니다. 한 레이어가 실패해도 다른 레이어가 여전히 보호를 제공합니다.

Source:

Rate Limiting Is Not One Tool – It’s Two

ApproachWhat It DoesCaller Experience
RejectionReturns 429 Too Many Requests. The request is over the limit and is rejected.Caller must handle the error.
Delay (queueing)Holds the request in a queue and releases it when the rate allows. The request is delayed, not rejected.Caller sees a slower response but no error.

Both achieve the same goal—enforcing a rate—but they provide completely different experiences.

The key question: When do you reject, and when do you delay?

  • Reject when an external connection is being held open (e.g., a user’s HTTP connection).
  • Delay when you can safely buffer the request and release it later without breaking the client’s expectations.

TL;DR

  • Load shedding → 서버 자체를 보호합니다.
  • Rate limiting → 악의적인 호출자로부터 시스템을 보호합니다.
  • Adaptive throttling → 하위 서비스들을 보호합니다.

이들을 순서대로 실행하세요 (load shedding → rate limiting → adaptive throttling) 하면 효율성과 복원력을 최대화할 수 있습니다.

Rate‑Limiting: Reject or Delay?

규칙은 간단합니다:

Reject – 호출자가 단순히 연결을 기다리고 있을 때.
Delay – 기다릴 여유가 있을 때.

아래는 선택이 왜 중요한지를 보여주는 일반적인 상황들입니다.

1. Connection‑Pool Exhaustion

“당신이 그 연결을 잡고 있다는 것은 — 스레드, 소켓, 메모리를 차지하고 있다는 뜻입니다.
500명의 사용자를 지연시키면 연결 풀을 다 소진하게 됩니다. 이제 제한 이하의 정상 사용자조차 연결을 얻지 못합니다.
당신의 레이트 리미터가 나쁜 사용자에게 너무 친절해서 좋은 사용자에게 장애를 일으킨 겁니다.
빠르게 Reject 하세요. 연결을 해제하고, 클라이언트의 재시도 로직에 맡기세요.”

2. External API Rate Limits (e.g., Stripe)

“시스템이 요청이 성공해야 할 때 Delay 하세요.
Stripe 결제 API를 호출하고 있습니다. 그들의 제한을 알고 있죠: 100 req/s.
101번째 요청은 실패할 필요가 없습니다 — 다음 초의 예산이 생길 때까지 10 ms만 기다리면 됩니다.
만약 Reject한다면 재시도 로직, 백오프 타이머, 데드레터 큐, 재시도 모니터링 등 전체 인프라를 구축해야 합니다. 이는 ‘그냥 기다려’ 로 해결되는 문제를 복잡하게 만드는 셈이죠.”

3. Public API Burst Traffic

“고객으로부터 폭발적인 트래픽이 들어옵니다. Reject 하세요. 429를 즉시 반환합니다.
고객의 SDK는 지수 백오프를 포함한 재시도 기능을 가지고 있습니다. 서버는 마이크로초 안에 거부 응답을 처리하고 다음 작업으로 넘어갑니다.
만약 Delay한다면 500개의 연결이 열려 있어 연결 풀이 고갈되고, 모든 사용자가 장애를 겪게 됩니다.”

4. Bulk Email Sends (SendGrid)

“SendGrid를 통해 50 000개의 마케팅 이메일을 보냅니다.
Delay 합니다. SendGrid는 500 req/s를 허용합니다. 50 000개를 모두 큐에 넣고 500 /s 속도로 흘려보내면 100 s가 걸리지만 모든 이메일이 전달됩니다.
만약 Reject한다면 첫 번째 초에 49 500개의 이메일이 반송됩니다. 그러면 데드레터 큐와 재시도 스케줄링을 구축해야 하는데, 이는 ‘차례를 기다려’ 로 완전히 해결되는 문제입니다.”

5. gRPC Internal Traffic

“gRPC 서버가 상위 서비스로부터 내부 트래픽을 받습니다. Reject 하세요. RESOURCE_EXHAUSTED를 반환합니다.
상위 서비스의 적응형 스로틀러(Layer 3)가 오류를 감지하고 자동으로 백오프합니다. 시스템이 스스로 회복됩니다.
만약 Delay한다면 상위 서비스의 gRPC 데드라인이 큐에 대기 중인 요청 때문에 만료됩니다. 타임아웃 오류는 깔끔한 거부보다 더 나쁘며, 상위 서비스는 *‘서버가 느리다’*와 *‘레이트‑리밋당했다’*를 구분할 수 없습니다.”

6. Batch Job Scraping a Partner API

“배치 작업이 파트너 API에서 10 000개의 레코드를 매일 밤 스크랩합니다.
Delay 합니다. 파트너는 50 req/s를 허용합니다. 완벽하게 속도를 맞추면 3.3 분이 걸리고 모든 요청이 성공하며 파트너는 스파이크를 전혀 보지 못합니다.
만약 Reject한다면 9 950개의 요청이 즉시 실패하고 재시도 로직이 작동해 파트너를 20 분 동안 두드리게 됩니다. 깔끔한 3‑분 크롤링이 사라지는 것이죠.”

7. User‑Facing Payment Endpoint

“체크아웃 중에 사용자가 결제 엔드포인트를 호출합니다. Reject 하세요.
사용자는 ‘지금 결제하기’ 버튼을 보게 됩니다. 200 ms 정도의 거부와 ‘다시 시도해 주세요’ 메시지는 5 초 지연으로 페이지가 멈춘 것처럼 보이게 하는 것보다 훨씬 좋습니다. 페이지를 새로 고쳐 중복 결제가 발생하는 상황을 방지할 수 있습니다.”

TL;DR

상황조치이유
호출자가 단순히 무료 연결만 필요Reject (예: 429, RESOURCE_EXHAUSTED)즉시 리소스를 해제; 클라이언트가 백오프와 함께 재시도 가능
할당량이나 페이싱을 기다릴 여유가 있음Delay (queue, sleep, token bucket)추가 재시도 인프라 없이 성공적인 처리 보장
외부 서비스에 알려진 속도 제한이 있음Delay 예산이 확보될 때까지불필요한 실패와 하위 시스템 재시도 폭풍 방지
사용자 경험이 지연에 민감Reject 명확한 메시지와 함께 빠르게UI 정지 및 중복 작업 방지
0 조회
Back to Blog

관련 글

더 보기 »

URL Shortener 설계

URL shortener 설계는 가장 인기 있는 system‑design 인터뷰 질문 중 하나입니다. 겉보기에는 간단해 보이지만, scalability와 database에 대한 이해도를 테스트합니다.

국가 백신 예약 및 접종 시스템

🌱 How It Started 몇 년 전, 나는 시스템‑design 인터뷰를 받았다. 면접관이 나에게 다음 시나리오를 제시했다: > Design a national vaccine appointment booking system...