Rate Limiting vs. Throttling

Rate Limiting과 Throttling은 API 설계와 관리에서 핵심적인 요소로, 시스템의 안정성과 보안을 유지하는 데 중요한 역할을 한다.

Rate Limiting과 Throttling은 모두 시스템 보호와 최적화를 위한 중요한 기술이지만, 그 목적과 구현 방식에는 명확한 차이가 있다. Rate Limiting은 특정 시간 내 허용되는 요청 수를 제한하여 남용을 방지하는 데 중점을 두는 반면, Throttling은 요청 처리 속도를 조절하여 시스템 리소스를 효율적으로 사용하는 데 중점을 둔다.

실제 애플리케이션에서는 두 기술을 함께 사용하여 더욱 견고하고 효율적인 시스템을 구축하는 것이 일반적입니다. Rate Limiting을 통해 과도한 요청을 차단하고, Throttling을 통해 허용된 요청을 적절한 속도로 처리함으로써 시스템의 안정성과 성능을 모두 확보할 수 있다.

효과적인 트래픽 관리 전략을 수립할 때는 애플리케이션의 특성, 사용자 패턴, 인프라 제약 등을 고려하여 Rate Limiting과 Throttling의 매개변수를 신중하게 조정해야 한다. 또한 지속적인 모니터링과 분석을 통해 변화하는 환경에 맞게 전략을 발전시켜 나가는 것이 중요하다.

개념적 이해

Rate Limiting (속도 제한)

Rate Limiting은 지정된 시간 간격 내에 수행할 수 있는 요청 또는 작업의 수를 제한하는 기술이다. 이는 주로 API 서버나 웹 서비스가 과도한 요청으로부터 보호되도록 설계되었다. 예를 들어, “사용자당 분당 최대 100개의 요청"과 같은 제한을 설정할 수 있다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// Node.js에서의 간단한 Rate Limiting 구현 예시
const rateLimits = {};
const WINDOW_SIZE_MS = 60000; // 1분
const MAX_REQUESTS = 100; // 분당 최대 요청

function isRateLimited(userId) {
  const currentTime = Date.now();
  const windowStart = Math.floor(currentTime / WINDOW_SIZE_MS) * WINDOW_SIZE_MS;
  
  // 사용자의 현재 윈도우 요청 상태 초기화
  if (!rateLimits[userId] || rateLimits[userId].windowStart !== windowStart) {
    rateLimits[userId] = {
      windowStart,
      count: 0
    };
  }
  
  // 요청 수 증가 및 제한 확인
  rateLimits[userId].count++;
  return rateLimits[userId].count > MAX_REQUESTS;
}

// 사용 예시
app.get('/api/resource', (req, res) => {
  const userId = req.user.id;
  
  if (isRateLimited(userId)) {
    return res.status(429).send('Too Many Requests');
  }
  
  // 요청 처리 계속 진행
});

Throttling (조절)

Throttling은 지정된 시간 동안 요청 또는 작업의 처리 속도를 제어하는 기술이다. 이는 요청을 완전히 차단하기보다는 처리 속도를 균일하게 분산시켜 시스템 리소스를 효율적으로 사용할 수 있게 한다. 예를 들어, “초당 10개의 요청만 처리"하도록 설정할 수 있다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Node.js에서의 간단한 Throttling 구현 예시
const REQUESTS_PER_SECOND = 10;
const INTERVAL_MS = 1000; // 1초

let processedRequestsCount = 0;
let lastResetTime = Date.now();

function processRequestWithThrottling(request) {
  const currentTime = Date.now();
  
  // 1초마다 카운터 초기화
  if (currentTime - lastResetTime >= INTERVAL_MS) {
    processedRequestsCount = 0;
    lastResetTime = currentTime;
  }
  
  // 처리 속도 제어
  if (processedRequestsCount < REQUESTS_PER_SECOND) {
    processedRequestsCount++;
    return processRequest(request); // 실제 요청 처리
  } else {
    // 현재 초의 할당량을 초과한 경우 대기열에 추가하거나 지연 처리
    setTimeout(() => {
      processRequestWithThrottling(request);
    }, INTERVAL_MS - (currentTime - lastResetTime));
  }
}

Rate Limiting과 Throttling의 차이점

엄밀히 말하면, Rate Limiting과 Throttling은 미묘한 차이가 있다:

  • Rate Limiting: 정해진 제한을 초과하면 요청을 거부한다.
  • Throttling: 요청 속도를 조절하여 제한에 도달했을 때 요청을 지연시키거나 대기열에 넣는다.

하지만 실무에서는 이 두 용어가 종종 혼용되어 사용된다.

Rate Limiting이 필요한 이유

  1. 시스템 안정성 보장
    과도한 요청은 서버 과부하를 일으켜 전체 시스템의 성능 저하나 장애를 유발할 수 있다. Rate Limiting은 이러한 위험을 방지한다.

  2. 비용 절감 및 자원 관리
    API 호출에는 서버 처리 시간, 네트워크 대역폭, 데이터베이스 쿼리 등 비용이 발생한다. Rate Limiting은 이러한 자원 소비를 예측 가능한 수준으로 유지한다.

  3. 보안 강화
    Rate Limiting은 무차별 대입 공격(Brute Force Attack), 서비스 거부 공격(DDoS), 자격 증명 스터핑(Credential Stuffing) 등의 공격을 감지하고 방어하는 데 도움이 된다.

  4. 공정한 사용 보장
    특정 사용자나 클라이언트가 API 자원을 독점하는 것을 방지하여 모든 사용자가 적절한 서비스 품질을 경험할 수 있도록 한다.

사용 사례 및 적용 분야

Rate Limiting 사용 사례

  1. API 보호: 남용 및 DoS 공격으로부터 API를 보호한다.
  2. 공정한 사용 보장: 모든 사용자가 공정하게 리소스에 접근할 수 있도록 한다.
  3. 비용 관리: 서드파티 API 사용 비용을 제한한다.
  4. 계층화된 서비스 제공: 유료 및 무료 서비스 등급에 따라 다른 제한을 적용한다.
  5. 봇 및 크롤러 제한: 과도한 웹 크롤링을 방지한다.
실제 사례 연구
GitHub API

GitHub API는 다양한 수준의 Rate Limiting을 구현한다:

  • 인증되지 않은 요청: 시간당 60회
  • 인증된 요청: 시간당 5,000회
  • 그래프 API: 시간당 5,000점 (쿼리 복잡성에 따른 포인트 시스템)

이 계층화된 접근 방식은 서비스의 안정성을 유지하면서도 다양한 사용자 요구를 수용한다.

Twitter API

Twitter는 앱별, 사용자별, 엔드포인트별로 세분화된 Rate Limiting을 적용한다:

  • 일부 엔드포인트: 15분당 15-450회(등급에 따라 다름)
  • 스트리밍 API: 실시간 데이터에 대한 별도 제한
  • 검색 API: 15분당 180-450회

이를 통해 플랫폼 부하를 관리하면서도 다양한 사용 사례를 지원한다.

Throttling 사용 사례

  1. 네트워크 트래픽 관리: 네트워크 대역폭을 효율적으로 사용한다.
  2. 데이터베이스 부하 분산: 데이터베이스에 대한 동시 쿼리 수를 제한한다.
  3. 배치 처리 최적화: 대량 작업의 처리 속도를 조절한다.
  4. 백그라운드 작업 관리: 시스템 리소스를 효율적으로 사용하도록 작업 처리 속도를 조절한다.
  5. 서비스 품질 보장: 높은 부하 상황에서도 일정 수준의 서비스 품질을 보장한다.

사례 연구: AWS S3는 초당 요청 수를 자동으로 조절(throttle)하여 서비스의 안정성을 보장한다. 갑작스러운 요청 증가 시 ‘503 Slow Down’ 오류를 반환하면서 클라이언트에게 요청 속도를 줄이라는 신호를 보낸다.

구현 시 고려사항

Rate Limiting 구현 시 고려사항

  1. 분산 시스템에서의 동기화: 여러 서버 간 Rate Limit 정보를 공유해야 한다.
  2. 저장소 선택: Redis와 같은 인메모리 데이터 저장소가 자주 사용된다.
  3. 정교한 식별자 선택: IP, 사용자 ID, API 키 등 적절한 식별자를 선택해야 한다.
  4. 정책 결정: 제한 초과 시 요청 거부, 대기열 추가, 또는 우선순위 낮추기 등의 정책이 필요하다.
  5. 클라이언트 알림: HTTP 429 상태 코드 및 X-RateLimit-* 헤더를 통해 클라이언트에게 제한 상태를 알린다.
1
2
3
4
5
6
7
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1612816120

{"error": "Rate limit exceeded. Try again in 60 seconds."}

Throttling 구현 시 고려사항

  1. 병목 지점 식별: 시스템의 어떤 부분이 병목 현상을 일으키는지 파악해야 한다.
  2. 적절한 조절 속도 선택: 너무 낮으면 시스템 활용도가 떨어지고, 너무 높으면 효과가 없다.
  3. 대기열 관리: 조절된 요청을 저장할 적절한 대기열 메커니즘이 필요하다.
  4. 타임아웃 처리: 오래된 요청은 타임아웃 처리해야 한다.
  5. 모니터링 및 조정: 시스템 성능을 모니터링하고 조절 매개변수를 동적으로 조정해야 한다.

장단점 비교

Rate Limiting의 장단점

장점:

  • 시스템 과부하 방지
  • API 남용 및 악의적인 공격 차단
  • 비용 제어 (특히 유료 API 사용 시)
  • 공정한 리소스 분배
  • 비즈니스 모델 지원 (무료/유료 티어 구분)

단점:

  • 정당한 트래픽 급증 시 사용자 경험 저하
  • 분산 환경에서 구현 복잡성
  • 적절한 한도 설정의 어려움
  • 클라이언트 측 처리 로직 필요

Throttling의 장단점

장점:

  • 시스템 리소스의 균일한 사용
  • 예측 가능한 성능 제공
  • 버스트 트래픽 처리 능력
  • 백그라운드 처리 최적화
  • 시스템 안정성 향상

단점:

  • 지연 시간 증가
  • 대기열 관리의 오버헤드
  • 복잡한 구현이 필요할 수 있음
  • 동적 조절의 어려움

Rate Limiting과 Throttling 함께 사용하기

실제 시스템에서는 종종 Rate Limiting과 Throttling을 함께 사용하여 더 강력한 트래픽 관리 솔루션을 구축한다:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// Rate Limiting과 Throttling을 함께 사용하는 예시
const rateLimits = {};
const requestQueue = [];
const RATE_LIMIT = 1000; // 사용자당 시간당 최대 요청 수
const THROTTLE_RATE = 10; // 초당 처리할 요청 수

// Rate Limiting 체크
function checkRateLimit(userId) {
  const now = Date.now();
  const hourStart = Math.floor(now / 3600000) * 3600000;
  
  if (!rateLimits[userId] || rateLimits[userId].hourStart !== hourStart) {
    rateLimits[userId] = { hourStart, count: 0 };
  }
  
  rateLimits[userId].count++;
  return rateLimits[userId].count <= RATE_LIMIT;
}

// 요청 처리 함수
app.post('/api/resource', (req, res) => {
  const userId = req.user.id;
  
  // Rate Limiting 적용
  if (!checkRateLimit(userId)) {
    return res.status(429).send('Rate limit exceeded');
  }
  
  // 요청을 대기열에 추가
  requestQueue.push({
    userId,
    data: req.body,
    res: res
  });
});

// Throttling을 통한 요청 처리
setInterval(() => {
  const batchSize = Math.min(THROTTLE_RATE, requestQueue.length);
  
  for (let i = 0; i < batchSize; i++) {
    const request = requestQueue.shift();
    processRequest(request);
  }
}, 1000); // 1초마다 실행

function processRequest(request) {
  // 실제 요청 처리 로직
  const result = processData(request.data);
  request.res.json(result);
}

Rate Limiting과 Throttling 비교

특성Rate LimitingThrottling
주요 목적특정 시간 내 허용되는 요청 수를 제한요청 처리 속도를 균일하게 조절
행동 방식제한 초과 시 요청 거부(HTTP 429)제한 초과 시 요청 지연 또는 대기열에 추가
보호 대상시스템 남용, DoS 공격, 비용 제어시스템 리소스, 처리 성능
시간 범위분, 시간, 일 단위의 긴 시간 범위밀리초, 초 단위의 짧은 시간 범위
구현 방식고정/슬라이딩 윈도우, 토큰 버킷고정 속도 제어, 지연 기반, 적응형 조절
저장소 요구사항카운터 및 타임스탬프 저장 필요대기열 관리 시스템 필요
클라이언트 영향거부된 요청에 대응해야 함응답 지연 처리 필요
사용 사례API 보호, 공정한
사용 보장, 티어드 서비스네트워크 트래픽, 배치 처리, 백그라운드 작업
장점남용 방지, 비용 제어, 리소스 보호균일한 처리, 예측 가능한 성능, 버스트 처리
단점합법적 트래픽 거부, 구현 복잡성지연 발생, 대기열 관리 오버헤드
HTTP 상태 코드429 Too Many Requests일반적으로 지연 후 200 OK 또는 503 Service Unavailable
대표적 알고리즘고정 윈도우, 슬라이딩 윈도우, 토큰 버킷리키 버킷, 고정 속도 제어, 적응형 조절
적용 계층API 게이트웨이, 애플리케이션 서버데이터베이스, 백엔드 서비스, 배치 처리기
확장성 고려사항분산 시스템에서 카운터 동기화분산 대기열 관리
모니터링 지표거부된 요청 수, 제한 도달 빈도평균 처리 시간, 대기열 길이, 지연 시간

용어 정리

용어설명

참고 및 출처