선착순 이벤트 쿠폰 발급 시스템을 구현하면서, 아키텍처 개선을 통한 트래픽 및 성능 이슈를 해결한 과정을 다루고 있습니다. 처음에는 간단한 구조에서 Redis를 활용한 비동기 처리구조로 개선하는 과정을 설명해보겠습니다. 

🔍 기존 쿠폰 발급 서버의 문제점

기존 쿠폰 발급 시스템 구조

초기 서버구조

  • API 서버는 사용자의 요청이 들어오면 바로 DB 트랜잭션을 통해 쿠폰 발급 처리(발급 수량 감소, 중복 검사, 발급 내역 저장)를 진행합니다.
  • 요청량이 적을 땐 문제 없이 작동하겠지만, 다수의 사용자가 동시에 몰리는 선착순 이벤트를 다루는 해당 프로젝트에서 트래픽이 순간적으로 몰리면 DB에 과부하가 걸려 성능 저하 및 장애가 발생할 가능성이 컸습니다.

🔍 문제점 분석 및 개선방향 설정

위 구조에서 발견한 문제점은 다음과 같습니다.

문제점  : DB 부하 증가 및 성능 저하

  • DB 부하 증가: 동시 요청이 많아지면 트랜잭션 충돌 및 Lock 경합 발생 가능.
  • 동시성 문제  : 선착순 이벤트에서 동시에 여러 요청이 들어오면 데이터 정합성이 깨질 가능성이 있음. (중복 발급, 재고 초과 발급)
  • API 서버 증가(Scale-out)를 하더라도, API 서버 → DB로 바로 연결되므로, API 서버를 여러 개 추가하더라도 모든 요청이 결국 하나의 DB로 집중됨 ( DB병목 현상 발생시 문제)

📌 개선 방향 설정  

위의 문제를 해결하기 위해 다음과 같은 3가지의 개선방향을 설정하고, 이를 중심으로 서버 구조를 개선하였습니다.

  • 1️⃣ 유저 트래픽과 쿠폰 발급 트랜잭션을 명확히 분리
  • 2️⃣ Redis Queue 기반 비동기 쿠폰 발급 시스템 도입
  • 3️⃣ API 서버와 쿠폰 발급 서버 역할 분리

💡 최종 개선 구조 (Redis Queue 기반 비동기 처리)

최종적으로 적용한 Redis Queue 기반의 아키텍처 구조 흐름은 다음과 같습니다. 

개선된 구조

  • 쿠폰 API 서버는 Redis Set을 사용해 중복 발급 및 재고 관리를 빠를게 처리하고, 발급 요청을 Redis Queue에 저장
  • 쿠폰 발급 서버Redis Queue에서 비동기적으로 요청을 읽어 DB 트랜잭션만 처리하여 부하를 분산

💡 개선된 쿠폰 발급 시스템 핵심 

앞서 설정한 3가지의 개선방향을 토대로, 개선된 쿠폰발급 시스템의 핵심은 다음과 같습니다.

✅ 유저 트래픽과 쿠폰 발급 트랜잭션을 명확히 분리

  • 기존 문제점 : 모든 사용자 요청이 곧바로 DB 트랜잭션으로 연결되어 MySQL에 부담을 주었습니다.
  • 이를 개선하여 모든 사용자 요청은 Redis에서 처리하고, DB와의 연결을 최소화하여 MySQL의 트래픽을 제어했습니다.
  • Redis Set의 빠른 읽기/쓰기를 통해 동시 접속자 처리 능력을 증가시켰고 Redis Lua Script를 통해 동시성문제를 해결하였습니다.
    • Redis Set은 중복된 데이터를 허용하지 않아 사용자의 중복 요청을 빠르게 방지할 수 있고, 추가, 조회 연산이 모두 O(1)의 시간 복잡도를 가짐
    • Redis는 기본적으로 하나의 스레드에서 명령을 처리하기 때문에, Redis Lua Script가 실행되면 해당 스크립트가 끝날때까지 다른 요청을 처리하지 않으므로, 원자성이 보장됨

✅ Redis Queue 기반 비동기 쿠폰 발급 시스템 도입

비동기 메시지 큐로는 Kafka를 많이 사용하지만, 해당 프로젝트에서는Kafka에 대한 지식이 부족했기 때문에,  Redis List를 사용하여 Queue를 구현하였습니다. 
  • 기존 문제점 동기 방식의 트랜잭션 처리 구조는 DB 성능 저하의 주된 원인이었습니다.
  • 이를 개선하기 위해 Redis List Queue를 도입하여 사용자 발급 요청을 Redis에 먼저 적재한 뒤, 별도의 서버가 Queue에서 요청을 Pull(꺼내서) 비동기적으로 쿠폰 발급 트랜잭션을 수행하도록 했습니다.
  • API 서버는 더 이상 DB 트랜잭션 처리와 연결되지 않고, 요청의 빠른 적재에 집중할 수 있게 되어 처리 속도를 높였고, 확장성이 향상 되었습니다.

✅  API 서버와 쿠폰 발급 서버 역할 분리

  • 발급 요청을 처리하는 API 서버와 쿠폰 발급을 실제로 수행하는 발급 전용 서버를 분리했습니다.
  • API 서버는 Redis에 요청을 보내는 작업만 수행하여 빠른 응답속도를 유지할 수 있게 했으며, 쿠폰 발급 서버는 Queue에서 요청을 읽어 실제로 MySQL 트랜잭션을 처리하는 작업만을 수행하도록 하였습니다.

🚩 개선 후 성능 테스트 결과

해당 테스트 결과는 개선한 서버 구조만으로 성능이 향상된 점이 아니라, 동시성 문제, 캐싱 전략, Redis 명령어 최적화등과 함께 구조 개선 결합이 이루어진 결과입니다. 
 

계층적 캐싱(Caffeine + Redis)을 도입하여 쿠폰 발급 시스템 성능 최적화하기

선착순 이벤트 쿠폰 발급 시스템을 구현하면서 Caffeine 로컬 캐시 + Redis 캐시를 활용한 계층적 캐싱 구조를 적용하여 성능 최적화 과정을 담고있습니다. 📌 캐시(Cache)란?자주 사용되는 데이터나

wjdgns4385.tistory.com

 

Redis Lua Script를 활용한 쿠폰발급 동시성 제어 및 성능 개선기

선착순 이벤트 쿠폰 발급 시스템을 구현하면서, 발생하는 동시성 문제를 해결하고, 성능이슈를 해결하는 과정을 다루고있습니다. 결론적으로는, Redisson 락의 성능 한계를 극복하고, Redis Lua Scrip

wjdgns4385.tistory.com


Locust 부하테스트 결과

  • 테스트 환경:Locust (동시 접속 유저 5000명, Ramp-up rate 500), API 서버 Worker 3대
  • TPS (초당 처리량):  2000+ 이상 유지
  • 평균 응답 속도:  100ms 이하
  • 성공률: 99.5% 이상 (실패율 0.5% 미만 유지)

시스템 리소스 모니터링 결과 

  • MySQL CPU: 평균 3.05% ~ 최대 5.61% → 비동기 처리 덕분에 매우 안정적 상태 유지, 추가 부하 감당 가능
  • Redis CPU: 평균 1.93% ~ 최대 2.58%, 초당 명령 처리량 43,800회 → 여유있는 상태,  추가 부하 감당 가능

  • API 서버의 CPU가 최대 90%이상까지 증가했으나, RedisMySQL의 CPU가 여유로운 상태 덕분에 추가 부하가 가능한 상태 → 서버 증설(스케일 아웃) 및 로드밸런싱등의 도입으로 추가적인 성능 개선이 가능한 구조
5jeong