대용량 트래픽 선착순 이벤트 서버 개발기 (feat. Redis, Kafka)

Jayson·2025년 8월 23일
0
post-thumbnail

들어가며: 감사의 마음을 담아, 1500명에게

모든 프로젝트에는 끝이 있습니다. 제가 참여했던 '터닝(Terning)' 프로젝트 역시 팀 내부적으로 서비스를 종료하기로 결정했습니다. 하지만 그냥 끝내고 싶지는 않았습니다. 그동안 터닝을 아껴준 약 1,500명의 소중한 사용자들에게 감사의 마음을 전하고 싶었고, 그 방법으로 작은 선물을 드리기로 했습니다.

문제는 '어떻게'였습니다. 1,500명의 사용자가 한정된 선물을 받기 위해 동시에 몰릴 것이 분명했습니다. 이는 곧 대규모 트래픽과의 싸움을 의미했습니다. 이 문제를 해결하고 감사의 마음을 온전히 전하기 위해, '터닝 페어웰(Terning Farewell)' 이라는 이름의 이별 선물 신청 서비스를 혼자서 개발하기로 결심했습니다.

기획, 디자인, 프론트엔드 개발은 AI의 도움을 받아 빠르게 진행하고, 저는 가장 자신 있고 집중하고 싶었던 서버 개발에 모든 역량을 쏟아부었습니다. 이 프로젝트는 제게 단순한 토이 프로젝트가 아니었습니다. 그동안 학습했던 고가용성 아키텍처, 분산 시스템, 비동기 처리와 같은 개념들을 실제 트래픽이 예상되는 서비스에 적용해볼 수 있는 최고의 기회였습니다.

이 글에서는 1,500명의 동시 접속을 안정적으로 처리하기 위해 어떻게 시스템을 설계하고, 어떤 기술들을 사용했는지 그 여정을 공유하고자 합니다.


시스템 아키텍처: 어떻게 트래픽을 감당할까?

이 프로젝트의 핵심은 '분산과 비동기'입니다. 각 컴포넌트는 다음과 같은 역할을 수행합니다.

  • Nginx: 최전방에서 사용자의 요청을 받아들이고, API 요청을 백엔드 서버로 전달하는 관문 역할을 합니다.
  • Spring Boot (Application Server): 사용자의 요청을 받아 인증, 중복 신청 방지, 재고 확인 등 핵심 비즈니스 로직을 수행합니다. DB에 직접 접근하는 대신, 모든 요청을 Redis와 Kafka에 전달하여 빠른 응답 속도를 보장합니다.
  • Redis: In-memory 데이터 저장소의 빠른 속도를 활용해 선착순 대기열재고 관리를 담당합니다. 모든 요청이 DB로 향하는 것을 막는 강력한 방패 역할을 합니다.
  • Kafka: 안정적인 데이터 처리를 위한 메시지 큐입니다. 서버는 신청 정보를 Kafka에 보내기만 하고 즉시 사용자에게 응답하며, 실제 DB 저장이나 이메일 발송 같은 시간 소요가 큰 작업은 Kafka Consumer가 비동기적으로 처리합니다.
  • MySQL (RDS): 모든 성공적인 신청 내역이 최종적으로 저장되는 데이터베이스입니다. Kafka를 통해 검증되고 정제된 데이터만 들어오므로 과부하로부터 안전합니다.

핵심 기능 플로우

사용자 경험은 단순하지만, 서버 내부는 안정성을 위해 여러 단계로 나뉩니다.

  1. 사전 인증: 사용자가 이메일 인증을 요청하면, 서버는 인증 코드를 생성해 Redis에 저장하고 사용자에게 이메일을 발송합니다. 사용자는 받은 코드로 본인 인증을 완료합니다.
  2. 빠른 신청 접수: 인증된 사용자가 '선물 신청'을 누르면, 서버는 Redis의 원자적 연산(Atomic Operation)을 사용해 선착순 재고가 있는지 확인합니다.
  3. 즉시 응답과 비동기 처리: 재고가 있다면, 신청 정보를 Kafka에 메시지로 발행한 직후 사용자에게 "신청이 정상 접수되었습니다"라는 응답을 즉시 보냅니다.
  4. 안전한 데이터 처리: 백그라운드에서 실행되는 Kafka Consumer가 큐에 쌓인 신청 정보를 순서대로 가져와 MySQL DB에 안전하게 저장하고, 최종 확정 안내 이메일을 발송합니다.

이 구조를 통해 사용자는 서버의 부하와 상관없이 쾌적한 경험을 하고, 시스템은 어떤 트래픽이 몰려와도 데이터를 유실 없이 안정적으로 처리할 수 있게 됩니다. 실제 배포된 서비스는 여기에서 확인하실 수 있습니다.

profile
Small Big Cycle

0개의 댓글