MMeshOps
Redis 실전: 서비스 장애를 막는 안전한 캐싱과 상태 관리
11예상 10중급

내 서버를 지키는 방패: API Rate Limiting 구현

무차별적인 API 요청으로부터 서버를 보호하기 위해 Redis를 활용해 사용자별 요청 횟수를 제한하는 방법을 배웁니다.

인기 있는 서비스는 항상 악의적인 트래픽이나 과도한 요청의 위협에 노출되어 있습니다. 한 사용자가 초당 수천 번의 로그인 요청을 보내거나, 귀중한 데이터를 싹쓸이해 간다면 서버는 견디지 못하고 다운될 것입니다.

이번 에피소드에서는 이처럼 과도한 요청을 제어하는 기술인 Rate Limiting(처리율 제한)이 무엇이며, 왜 Redis가 이 역할을 수행하기에 가장 완벽한 도구인지 알아봅니다.

Rate Limiting이란 무엇인가?

Rate Limiting(처리율 제한)은 특정 사용자나 IP가 정해진 시간 동안 서버에 요청할 수 있는 횟수를 제한하는 기술입니다.

"1분에 10회까지만 비밀번호 찾기 가능", "IP당 하루 1,000번까지만 API 호출 가능" 같은 규칙이 대표적인 예입니다. 이를 통해 무차별 대입 공격(Brute Force)을 막고, 소수의 사용자가 서버 자원을 독점하는 것을 방지합니다.

Rate Limiting 적용이 필수적인 곳

상황선택이유
비밀번호 확인로그인, 비밀번호 찾기무차별 대입(해킹) 방어
비용 발생 APISMS 발송, AI 텍스트 생성과금 폭탄 및 자원 낭비 방지
데이터 수집게시글 목록 조회, 상품 크롤링경쟁사의 무단 데이터 수집 지연

왜 Rate Limiting을 메인 DB에서 하지 않을까?

Rate Limiting을 구현하려면 "이 IP가 최근 1분 동안 몇 번 요청했는지"를 계속 기록하고 세어야 합니다. 만약 이 작업을 PostgreSQL 같은 메인 데이터베이스에서 한다면 어떤 일이 발생할까요?

요청이 들어올 때마다 메인 DB에 카운트를 업데이트하고 조회해야 하므로, 트래픽이 몰릴 때 오히려 Rate Limiting 시스템 자체가 병목을 일으켜 서비스 장애의 원인이 될 수 있습니다.

반면 Redis는 메모리 기반이라 카운트를 올리는 속도가 비교할 수 없이 빠릅니다. 트래픽의 최전선에서 방패 역할을 하려면 압도적으로 빠른 Redis가 필수적입니다.

고정 윈도우(Fixed Window) 카운터 패턴

가장 단순하면서도 실무에서 널리 쓰이는 Rate Limiting 패턴입니다. 시간 단위를 쪼개서(예: 1분) 해당 시간 단위마다 카운터를 만드는 방식입니다.

예를 들어 IP `192.168.0.1`의 "2026-07-12 10:15" 1분 동안의 요청 횟수를 제한한다면, 키 이름에 시간 정보를 포함시킵니다.

단순한 Rate Limiting 구현 (개념)

async function checkRateLimit(ip) {
  // 현재 시간의 '분' 단위까지만 추출 (예: 2026-07-12T10:15)
  const currentMinute = getCurrentMinuteString();
  const key = `ratelimit:ip:${ip}:${currentMinute}`;
  
  // Redis의 INCR 명령어: 값이 없으면 1로 생성, 있으면 1 증가시킴 (아주 빠름!)
  const count = await redis.incr(key);
  
  // 카운터가 메모리에 영원히 남지 않도록 2분 후 자동 삭제 (TTL 설정)
  if (count === 1) {
    await redis.expire(key, 120); 
  }
  
  if (count > 60) {
    return false; // 1분에 60회 초과 시 차단
  }
  return true; // 정상 요청 허용
}

서버 여러 대 환경에서의 Rate Limiting

웹 서버를 메모리 제한용으로 쓰면 안 되는 이유를 이전 에피소드에서 세션을 다루며 배웠습니다. Rate Limiting도 마찬가지입니다. 서버 A에 30번, 서버 B에 40번 요청을 분산해서 보내면 개별 서버는 제한을 넘지 않은 것으로 착각할 수 있습니다.

따라서 Rate Limiting도 모든 웹 서버가 중앙의 Redis 하나를 바라보고 횟수를 확인하도록 아키텍처를 설계해야 정확한 트래픽 제어가 가능합니다.

Rate Limiting 구현 시 주의점

오해 또는 실수

차단 기준을 웹 서버(Node.js 등) 메모리에서 계산함

바로잡기

여러 서버를 띄울 경우 차단 기준이 초기화되므로 Redis 같은 공통 저장소 사용

오해 또는 실수

카운터 키에 TTL(만료 시간)을 설정하지 않음

바로잡기

시간이 지난 과거의 카운터 데이터가 영원히 남아 메모리 누수 발생

개념 퀴즈

퀴즈 답을 맞춰야 학습 완료가 됩니다.

Rate Limiting(처리율 제한) 정보를 PostgreSQL 대신 Redis에 저장해야 하는 가장 큰 이유는 무엇인가요?

3줄 요약

  1. 1Rate Limiting은 특정 사용자의 과도한 API 호출이나 무차별 대입 공격으로부터 서버를 보호하는 방패입니다.
  2. 2빠른 응답 속도가 필수이므로 디스크 기반의 메인 DB 대신 메모리 기반의 Redis를 사용합니다.
  3. 3IP별, 사용자별로 카운터를 만들 때는 반드시 TTL을 설정해 과거의 제한 기록이 메모리를 낭비하지 않도록 해야 합니다.