본문으로 건너뛰기

챗봇 서비스의 안정성을 위한 사용자별 속도 제한(Rate Limit) 전략

Your chat bot needs a better rate limit strategy

작성자
발행일
2026년 03월 03일
https://thoughtbot.com/blog/chat-bot-per-user-rate-limits

핵심 요약

  • 1 OpenAI와 같은 LLM API는 조직 단위의 제한을 가지므로, 특정 사용자의 과도한 사용이 전체 서비스의 거부(DoS)를 유발하지 않도록 개별 사용자별 속도 제한이 필수적입니다.
  • 2 분당 요청 수(RPM)뿐만 아니라 토큰 사용량(TPM)도 함께 관리해야 하며, Redis의 증감 및 만료 기능을 활용하여 효율적인 고정 윈도우 방식의 제한을 구현할 수 있습니다.
  • 3 단순한 요청 거부 대신 백그라운드 작업을 통한 재시도 메커니즘을 도입하거나, 트래픽 급증에 대비한 버퍼를 고려하여 사용자별 할당량을 계산하는 정교한 전략이 필요합니다.

도입

최근 많은 서비스가 OpenAI와 같은 거대 언어 모델(LLM)을 통합하여 챗봇 기능을 제공하고 있습니다. 하지만 LLM API는 일반적인 API와 달리 분당 요청 수(RPM)와 분당 토큰 수(TPM)라는 복잡한 제한 정책을 조직 단위로 적용합니다. 만약 개별 사용자별로 적절한 속도 제한을 설정하지 않는다면, 단 한 명의 악의적이거나 과도한 사용자가 조직 전체의 할당량을 소진시켜 서비스 전체가 중단되는 상황이 발생할 수 있습니다. 본 글에서는 Ruby on Rails 환경에서 Redis를 활용하여 사용자별 RPM과 TPM을 효과적으로 제어하는 기술적 방법론을 제시합니다.

개별 사용자 속도 제한의 필요성

챗봇 기능은 다른 일반적인 기능보다 리소스를 훨씬 빠르게 소모합니다. 사용자는 짧은 시간 내에 여러 메시지를 보낼 수 있어 RPM이 급증하며, 대화 내용이 길어지거나 첨부 파일이 포함될 경우 컨텍스트 윈도우가 커져 TPM 역시 기하급수적으로 늘어납니다. 조직 단위의 제한을 공유하는 환경에서 특정 사용자의 과도한 사용은 다른 모든 기능의 마비를 초래하므로, 사용자 단위의 정교한 제어가 반드시 수반되어야 합니다.

Redis를 활용한 RPM(분당 요청 수) 제한 구현

Rails의 기본 속도 제한 기능도 유용하지만, 토큰 사용량과 같은 세밀한 제어를 위해서는 Redis와 같은 캐시 스토어를 직접 활용하는 것이 효율적입니다. - 고정 윈도우 방식: Redis의 INCR 명령어를 사용하여 요청 횟수를 카운트하고, EXPIRE를 통해 1분 뒤에 자동으로 초기화되도록 설정합니다. - 구현 예시: Usage 클래스를 정의하여 사용자 ID별로 고유한 키를 생성하고, 요청이 발생할 때마다 카운트를 증가시키며 제한 수치 초과 여부를 확인합니다.

TPM(분당 토큰 수) 기반의 정교한 제어

메시지의 길이는 토큰 사용량과 1:1로 매칭되지 않으며, 모델의 응답 토큰 또한 제한에 포함됩니다. 따라서 API 응답에서 제공하는 실제 토큰 사용 데이터를 추적해야 합니다. - 토큰 데이터 추출: OpenAI API 응답에는 입력(input), 출력(output), 추론(thinking) 토큰 정보가 포함됩니다. - 누적 추적: RPM 제한과 동일한 방식으로 Redis를 사용하되, 고정된 값(1)이 아닌 실제 사용된 총 토큰 수를 누적하여 관리합니다.

사용자별 할당량 계산 공식

조직의 전체 제한 수치를 사용자들에게 어떻게 배분할 것인지 결정하는 것이 중요합니다. 초기 단계의 서비스라면 다음과 같은 공식을 적용할 수 있습니다. - 공식: 사용자별 제한 = (조직 전체 제한 × 버퍼 계수) / 예상 동시 접속자 수 - 버퍼 계수: 갑작스러운 트래픽 급증에 대비하여 전체 용량의 80%(0.8) 정도로 설정하는 것이 안전합니다.

사용자 경험을 고려한 고급 전략: 백그라운드 작업 및 재시도

단순히 요청을 거부(Reject)하고 오류 메시지를 보여주는 것은 사용자 경험에 좋지 않습니다. 대신 ActiveJob을 활용한 비동기 처리 방식을 도입할 수 있습니다. - 재시도 메커니즘: 사용자가 속도 제한에 도달했을 때 즉시 오류를 내는 대신, 작업을 큐에 넣고 일정 시간(예: 15초) 후에 다시 시도하도록 설계합니다. - 상태 알림: 사용자에게는 현재 처리 중임을 알리는 로딩 상태를 보여주고, 백그라운드에서 처리가 완료되면 결과를 브로드캐스팅합니다. - 비즈니스 연계: 제한에 도달한 사용자에게 유료 플랜 업그레이드를 제안하거나, 더 저렴하고 제한이 넉넉한 하위 모델로 자동 전환하는 폴백 전략을 고려할 수 있습니다.

결론

사용자별 속도 제한은 단순한 기술적 제약을 넘어 서비스의 가용성과 비즈니스 지속성을 보장하는 핵심 요소입니다. Redis를 활용한 고정 윈도우 방식은 구현이 간단하면서도 강력한 성능을 제공하며, 토큰 기반의 정교한 제어는 예기치 못한 비용 발생을 방지합니다. 하지만 단순히 요청을 차단하는 것만이 정답은 아닙니다. 백그라운드 작업을 통한 재시도, 유료 플랜으로의 유도, 혹은 저렴한 모델로의 폴백(Fallback) 등 사용자 경험을 고려한 다양한 전략을 비즈니스 요구사항에 맞춰 선택해야 합니다. 이러한 다각도적인 접근은 안정적이고 확장 가능한 AI 서비스를 구축하는 밑거름이 될 것입니다.

댓글0

댓글 작성

댓글 삭제 시 비밀번호가 필요합니다.

이미 계정이 있으신가요? 로그인 후 댓글을 작성하세요.

0/1000
정중하고 건설적인 댓글을 작성해 주세요.