선착순 쿠폰 발급에서 Redis TTL을 활용한 역정규화 설계

송현진·2025년 7월 12일
0

프로젝트 회고

목록 보기
11/17

문제 상황

선착순 쿠폰 발급 시스템을 만들면서 가장 중요한 조건은 “한 유저가 하나의 쿠폰만 발급받을 수 있도록 보장”하는 것이었다. 즉, 중복 발급을 막고 동시에 만료 시간(유효기간)도 관리해야 했다. 전통적인 방식이라면 쿠폰 발급 내역을 DB에서 user_id, coupon_id로 조회하고 처리하겠지만 이 방식은 다음과 같은 문제를 가진다.

  • 트래픽이 많아질수록 DB 부하 증가
  • 발급 처리 전에 SELECT 쿼리 + 트랜잭션 비용이 발생
  • 실시간성이 중요한 선착순 시스템에 병목 요인

해결 방법: Redis를 활용한 역정규화 구조

이를 해결하기 위해 Redis에 userIdcouponId를 조합한 키를 만들고 TTL을 설정하는 방식으로 개선했다.

Key: coupon:{couponId}:user:{userId} -> 예: coupon:1:user:42
Value: 1 (혹은 발급 timestamp)
TTL: 쿠폰 유효 시간만큼 설정 (예: 1시간, 3일 등)

유저 42번이 1번 쿠폰을 이미 발급받았음을 의미한다.

작동 흐름

  1. 쿠폰 발급 시도 시 Redis에서 coupon:{couponId}:user:{userId} 키 존재 여부를 먼저 확인한다.

  2. 키가 없으면

    • Lua 스크립트를 통해 쿠폰 재고 차감한다.
    • 해당 키를 Redis에 등록 + TTL 설정
  3. 키가 이미 존재하면 중복 발급으로 판단하여 차단 한다.

이점

  • DB를 조회하지 않고도 중복 여부 판단 가능 -> 성능 향상
  • TTL을 활용해 쿠폰 유효기간 자동 만료 처리
  • userId, couponId를 key로 조합함으로써 빠른 존재 체크가 가능
  • 구조가 단순하고 확장성도 좋음 (ex. 쿠폰 외에 다른 이벤트에도 재사용 가능)

📝 느낀점

이 구조는 일반적인 정규화된 RDBMS 구조에서는 바로 떠올리기 어려운 방식이지만 Redis의 특성을 적극 활용한 역정규화 전략으로 볼 수 있다. 처음엔 key가 길어지는 것이 비효율적일까 고민했지만 성능 테스트 결과에서는 오히려 훨씬 빠르고 안정적인 동작을 보여줬다. 역정규화는 단순히 데이터를 중복 저장하는 게 아니라 특정 요구사항에 최적화된 형태로 데이터를 재배치하는 것이라는 점을 실전에서 체감할 수 있었다.

profile
개발자가 되고 싶은 취준생

0개의 댓글