수천 명의 동시 접속을 버텨내는 타임딜 아키텍처 방어 원리

1. 기술적 난제 (문제)

이커머스 타임딜 시스템의 가장 큰 기술적 난제는 **“수천 명이 100개의 한정된 재고를 두고 동시에 버튼을 누를 때 발생하는 트래픽 폭주(Burst)와 동시성(Concurrency) 이슈”**입니다. 모든 요청이 그대로 데이터베이스(RDBMS)로 향하게 되면 커넥션 풀이 고갈되고, 트랜잭션 데드락이나 타임아웃으로 인해 시스템 전체가 마비되는 결과를 초래합니다.

2. 해결을 위한 선택 (방어선 구축)

이 문제를 해결하기 위해 아키텍처 레벨에서 3중 방어선을 구축했습니다.

1차 방어선: Redis 재고 게이트 (DB 부하 원천 차단)

  • 전략: DB로 향하는 길목에 메모리 기반의 Redis를 배치합니다.
  • 원리: Redis의 단일 스레드 특성을 이용해 opsForValue().decrement()로 원자적(Atomic) 차감을 수행합니다.
  • 효과: O(1) 속도로 수천 명의 요청 중 100명의 승자만 통과시키고, 나머지는 DB에 닿기 전에 즉시 409 Sold Out으로 쳐냅니다.

2차 방어선: PG와 DB 트랜잭션의 완벽한 분리

  • 전략: 외부 API(결제 PG사) 호출 구간을 DB 트랜잭션 바깥으로 빼냅니다.
  • 원리: [DB 락 획득(PAYING 마킹) -> DB 락 반납] -> [PG 외부 통신] -> [DB 락 획득(PAID 저장 및 DB 재고차감)] 형태로 트랜잭션을 짧게 끊습니다.
  • 효과: PG 결제를 대기하는 수 초 동안 DB 커넥션(HikariCP)이 묶여서 고갈되는 현상을 방지합니다.

3차 방어선: 멱등성과 비관적 락 (다중 결제 방지)

  • 전략: 사용자의 중복 클릭(따닥)으로 인한 초과 결제를 차단합니다.
  • 원리: SELECT FOR UPDATE를 통해 동일한 주문번호의 요청을 DB 레벨에서 직렬화(Serialization)합니다. 첫 요청만 PAYING으로 넘어가고 나머지는 무시됩니다.

3. 그 선택의 대가와 극복 (인프라 한계와 데이터 정합성)

대가

Redis 캐시 레이어를 도입하고 트랜잭션을 분리함으로써 데이터 정합성(Redis 재고와 DB 재고의 불일치 위험) 문제가 대가로 따랐습니다. 또한 결제 실패 시 롤백 처리의 복잡도가 증가했습니다.

극복

결제 도중 사용자가 이탈하거나 잔액 부족으로 결제가 실패하면, 무거운 DB 롤백 대신 **Redis에만 increase()(+1)를 호출하여 재고를 복구(보상 트랜잭션)**하는 방식을 택했습니다. DB에는 상태만 FAILED로 남깁니다. 이러한 최종적 일관성(Eventual Consistency) 전략을 통해 복잡성을 극복하면서도, 고가의 대형 서버가 아닌 t3.medium 체급의 단일 EC2 인스턴스(Tomcat 400 스레드 튜닝)만으로도 DB 데드락 없이 안정적으로 방어해내는 고가용성 구조를 완성할 수 있었습니다.


Supported by gemini-3.0-pro preview