군만두의 IT 개발 일지

[스터디9] 05. 처리율 제한 장치의 설계 본문

학습일지/시스템 설계

[스터디9] 05. 처리율 제한 장치의 설계

mandus 2025. 7. 26. 21:43

목차

    4장. 처리율 제한 장치의 설계

    네트워크 시스템에서 처리율 제한 장치(Rate Limiter)는 클라이언트 또는 서비스가 보내는 트래픽의 처리율(rate)을 제어하기 위한 장치다. 이 장치는 특정 기간 내에 전송되는 클라이언트의 요청 횟수를 제한하며, API 요청 횟수가 임계치(threshold)를 넘어서면 추가로 도달한 모든 호출은 처리가 중단(block)된다.

    처리율 제한 장치의 장점

    • DoS(Denial of Service) 공격 방지: 악의적인 사용자가 과도한 요청을 보내 시스템 자원을 고갈시키는 것을 방지한다.
    • 비용 절감: 추가 요청에 대한 처리를 제한하면 서버를 많이 두지 않아도 되고, 우선순위가 높은 API에 더 많은 자원을 할당할 수 있다.
    • 서버 과부하 방지: 봇이나 사용자의 잘못된 이용 패턴으로 유발된 트래픽으로부터 서비스를 보호한다.

    1단계 문제 이해 및 설계 범위 확정

    시스템 설계 면접에서 처리율 제한 장치를 설계할 때 다음과 같은 요구사항을 명확히 해야 한다.

    기본 요구사항

    • 설정된 처리율을 초과하는 요청은 정확하게 제한한다.
    • 낮은 응답시간: 이 처리율 제한 장치는 HTTP 응답시간에 나쁜 영향을 주어서는 곤란하다.
    • 가능한 한 적은 메모리를 사용해야 한다.
    • 분산형 처리율 제한: 하나의 처리율 제한 장치를 여러 서버나 프로세스에서 공유할 수 있어야 한다.
    • 예외 처리: 요청이 제한되었을 때는 그 사실을 사용자에게 분명하게 보여주어야 한다.
    • 높은 결함 감내성: 제한 장치에 장애가 생기더라도 전체 시스템에 영향을 주어서는 안 된다.

    2단계 개략적 설계안 제시 및 동의 구하기

    처리율 제한 장치는 클라이언트 측 또는 서버 측에 둘 수 있다.

    클라이언트 측 구현

    • 장점: 구현이 간단하다.
    • 단점: 클라이언트의 요청은 쉽게 위변조가 가능하므로 안정적이지 않다.

    서버 측 구현

    두 가지 방법이 있다.

    1. 미들웨어로 구현: HTTP 요청을 통제하는 처리율 제한 미들웨어(middleware)를 만든다.
    2. API 게이트웨이에 구현: MSA 환경에서는 처리율 제한, SSL 종단, 사용자 인증, IP 허용 목록 관리 등의 기능을 API 게이트웨이(gateway)에 구현한다.

    구현 위치에 대한 지침

    • 현재 기술 스택이 서버 측에 기능 구현이 가능한지 점검한다.
    • 상황에 맞는 알고리즘을 사용한다. 제3 사업자가 제공하는 게이트웨이를 사용한다면 선택지는 제한될 수 있다.
    • MSA인 경우, 처리율 제한 장치는 보통 API 게이트웨이에 구현한다.
    • 충분한 인력이 없다면 상용 API 게이트웨이도 고려해보는 것이 좋다.

    처리율 제한 알고리즘

    처리율 제한 알고리즘의 기본 아이디어는 얼마나 많은 요청이 접수되었는지를 추적할 수 있는 카운터를 추적 대상별로 두고, 이 카운터의 값이 한도를 초과하면 한도를 넘어선 요청을 거부하는 것이다.

    1) 토큰 버킷 알고리즘 (Token Bucket)

    가장 널리 사용되는 알고리즘으로, 아마존과 스트라이프가 API 요청을 통제하기 위해 사용한다.

     

    동작 원리

    • 지정된 용량을 갖는 버킷이 있다.
    • 사전 설정된 양의 토큰이 주기적으로 버킷에 채워진다.
    • 토큰이 꽉 찬 버킷에는 더 이상 토큰이 추가되지 않는다.
    • 각 요청은 처리될 때마다 하나의 토큰을 사용한다.
    • 요청이 도착하면 버킷에 충분한 토큰이 있는지 검사한다.
      • 충분한 토큰이 있다면, 토큰을 하나 꺼내고 요청을 처리한다.
      • 충분한 토큰이 없다면, 해당 요청은 버려진다.

     

    파라미터

    • 버킷 크기: 버킷에 담을 수 있는 토큰의 최대 개수
    • 토큰 공급률(refill rate): 초당 몇 개의 토큰이 버킷에 공급되는가

     

    장점

    • 구현이 쉽다.
    • 메모리 사용량 측면에서 효율적이다.
    • 일시적인 트래픽 집중(traffic burst)을 처리할 수 있다.

     

    단점

    • 버킷 크기와 토큰 공급률이라는 두 개의 인자를 가지고 있어 적절하게 튜닝하는 것이 어렵다.

    2) 누출 버킷 알고리즘 (Leaky Bucket)

    토큰 버킷 알고리즘과 비슷하지만 '요청 처리율이 고정되어 있다'는 점이 다르다. 쇼피파이(Shopify)가 이 알고리즘을 사용한다.

     

    동작 원리

    • 보통 FIFO(First-in-First-Out) 큐로 구현한다.
    • 요청이 도착하면 큐가 가득 차 있는지 본다.
    • 빈자리가 있는 경우에는 큐에 요청을 추가한다.
    • 큐가 가득 차 있는 경우에는 새 요청을 버린다.
    • 지정된 시간마다 큐에서 요청을 꺼내어 처리한다.

     

    파라미터

    • 버킷 크기: 큐 사이즈와 같은 값
    • 처리율(outflow rate): 지정된 시간 당 몇 개의 항목을 처리할지 지정하는 값 (초 단위)

     

    장점

    • 큐의 사이즈가 고정되어 있어 메모리 사용량 측면에서 효율적이다.
    • 고정된 처리율을 가지고 있어 안정적 출력(stable outflow rate)이 필요한 경우에 적합하다.

     

    단점

    • 단시간에 많은 트래픽이 몰리는 경우 큐에는 오래된 요청들이 쌓이게 되고, 그 요청들을 제때 처리 못하면 최신 요청들이 버려진다.
    • 두 개 인자를 적절하게 튜닝하기 까다롭다.

    3) 고정 윈도 카운터 알고리즘 (Fixed Window Counter)

    동작 원리

    • 타임라인을 고정된 간격의 윈도로 나누고, 각 윈도마다 카운터를 붙인다.
    • 요청이 접수될 때마다 이 카운터의 값은 1씩 증가한다.
    • 이 카운터의 값이 사전에 설정된 임계치에 도달하면 새로운 요청은 새 윈도가 열릴 때까지 버려진다.

     

    장점

    • 메모리 효율이 좋다.
    • 이해하기 쉽다.
    • 윈도가 닫히는 시점에 카운터를 초기화하는 방식은 특정한 트래픽 패턴을 처리하기에 적합하다.

     

    단점

    • 윈도 경계 부근에 순간적으로 많은 트래픽이 집중될 경우 윈도에 할당된 양보다 더 많은 요청이 처리될 수 있다.

    4) 이동 윈도 로그 알고리즘 (Sliding Window Log)

    고정 윈도 카운터 알고리즘의 경계 문제를 해결한다.

     

    동작 원리

    • 이 알고리즘은 요청의 타임스탬프를 추적한다.
    • 타임스탬프 데이터는 보통 레디스(Redis)의 정렬 집합같은 캐시에 보관한다.
    • 새 요청이 오면 만료된 타임스탬프는 제거한다.
    • 새 요청의 타임스탬프를 로그에 추가한다.
      • 로그의 크기가 허용치보다 같거나 작으면, 요청을 시스템에 전달한다.
      • 그렇지 않은 경우, 처리를 거부한다.

     

    장점

    • 처리율 제한 메커니즘이 매우 정교하다.
    • 어느 순간의 윈도를 보더라도 허용되는 요청의 개수는 시스템의 처리율 한도를 넘지 않는다.

     

    단점

    • 거부된 요청의 타임스탬프도 보관하므로 다량의 메모리를 사용한다.

    5) 이동 윈도 카운터 알고리즘 (Sliding Window Counter)

    고정 윈도 카운터 알고리즘과 이동 윈도 로그 알고리즘을 결합한 것이다.

     

    계산 공식

    • 현재 1분간의 요청 수 + 직전 1분간의 요청 수 × 이동 윈도와 직전 1분이 겹치는 비율

     

    장점

    • 이전 시간대의 평균 처리율에 따라 현재 윈도의 상태를 계산하므로 짧은 시간에 몰리는 트래픽에도 잘 대응한다.
    • 메모리 효율이 좋다.

     

    단점

    • 직전 시간대에 도착한 요청이 균등하게 분포되어 있다고 가정한 상태에서 추정치를 계산하므로 다소 느슨하다.

    알고리즘 비교

    알고리즘 메모리 사용 정확도 구현 난이도 사용 사례
    토큰 버킷 낮음 높음 쉬움 일반적인 목적
    누출 버킷 낮음 높음 쉬움 안정적 처리율
    고정 윈도 낮음 중간 쉬움 특정 트래픽 패턴
    이동 윈도 로그 높음 매우 높음 복잡 정밀한 제어
    이동 윈도 카운터 낮음 높음 중간 균형잡힌 선택

    3단계 상세 설계

    처리율 제한 규칙

    처리율 제한 규칙은 보통 구성 파일(configuration file) 형태로 저장된다.

    # 마케팅 메시지를 하루에 5개까지만 보낼 수 있음
    domain: messaging
    descriptors:
      - key: message_type
        value: marketing
    rate_limit:
      unit: day
      requests_per_unit: 5
    
    # 클라이언트가 분당 5회 이상 로그인할 수 없도록 처리
    domain: auth
    descriptors:
      - key: auth_type
        value: login
    rate_limit:
      unit: minute
      requests_per_unit: 5

    처리율 한도 초과 트래픽의 처리

    • 요청이 한도 제한에 걸리면 API는 429 상태 코드(Too Many Requests)를 리턴한다.
    • 경우에 따라서 나중에 처리하기 위해 큐에 보관할 수 있다.

     

    처리율 제한 장치가 사용하는 HTTP 헤더

    • X-Ratelimit-Remaining: 윈도 내에 남은 처리 가능 요청의 수
    • X-Ratelimit-Limit: 매 윈도마다 클라이언트가 전송할 수 있는 요청의 수
    • X-Ratelimit-Retry-After: 한도 제한에 걸리지 않으려면 몇 초 뒤에 요청을 다시 보내야 하는지 알림

    경쟁 조건(Race Condition)

    분산 환경에서는 여러 서버가 동시에 카운터에 접근할 때 경쟁 조건이 발생할 수 있다.

    • 문제: Redis에서 Counter 3을 가져와 작업을 완료해 다시 +1 하기 전에 다른 요청이 Counter 3을 가져가서 두 요청이 Counter 4를 업데이트하는 현상
    • 해결방안:
      • Lock 사용 (시스템 성능 저하)
      • 루아 스크립트(Lua Script) 또는 Redis의 정렬 집합(Sorted Set) 사용

    동기화 이슈

    • 고정 세션(Sticky Session): 같은 클라이언트로부터의 요청은 항상 같은 처리율 제한 장치로 보낼 수 있도록 한다. (추천하지 않음)
    • 중앙 집중식 데이터 저장소: Redis같은 중앙 저장소를 사용한다.

    성능 최적화

    • 지연시간(latency) 감소: 사용자의 트래픽을 가장 가까운 Edge 서버로 전달한다.
    • 데이터 동기화: 최종 일관성 모델(eventual consistency model)을 사용한다.

    모니터링

    • 채택된 처리율 제한 알고리즘이 효과적인지 확인한다.
    • 정의한 처리율 제한 규칙이 효과적인지 확인한다.

    4단계 마무리

    추가로 논의할 수 있는 주제들

    • 경성(hard) vs 연성(soft) 처리율 제한
      • 경성 처리율 제한: 요청의 개수는 임계치를 절대 넘어설 수 없다.
      • 연성 처리율 제한: 요청의 개수는 잠시 동안은 임계치를 넘어설 수 있다.
    • 다양한 계층에서의 처리율 제한
      • 애플리케이션 계층(7번 계층) 외에도 다른 계층에서 처리율 제한이 가능하다.
      • Iptables를 사용하여 IP 주소에 처리율 제한을 적용한다.
    • 클라이언트 측에서 처리율 제한을 회피하는 방법
      • 클라이언트 측 캐시를 사용하여 API 호출 횟수를 줄인다.
      • 처리율 제한의 임계치를 이해하고 짧은 시간 동안 너무 많은 메시지를 보내지 않는다.
      • 예외나 에러를 처리하는 코드를 도입하여 클라이언트가 예외적 상황으로부터 우아하게 복구될 수 있도록 한다.
      • 재시도(retry) 로직을 구현할 때는 충분한 백오프(back-off) 시간을 둔다.

     

    ✔️ 복습하기
    1. 처리율 제한 장치의 장점은?
    2. 토큰 버킷 알고리즘과 누출 버킷 알고리즘의 차이점은?
    3. 이동 윈도 로그 알고리즘이 메모리를 많이 사용하는 이유는?
    4. 처리율 제한 장치가 사용하는 3가지 HTTP 헤더는?

     

    이 글은 『 가상 면접 사례로 배우는 대규모 시스템 설계 기초』 책을 학습한 내용을 정리한 것입니다.

    Comments