🎟️ Redis 입장권 기반 예약 시스템은 정말 중복 예약을 막을까?

2026. 4. 27. 11:49·프로젝트/공연 티켓팅 프로젝트

티켓팅 서비스에서 가장 위험한 순간 중 하나는
한 사용자가 동시에 여러 번 예약 요청을 보내는 상황입니다.

예를 들어

  • 예약 버튼 연타
  • 브라우저 여러 개 실행
  • 새로고침 반복
  • 악의적인 API 반복 호출

이런 상황에서 중복 예약이 발생하면

  • booking 중복 생성
  • booked_count 증가 오류
  • 초과 예약

문제가 발생할 수 있습니다.

 

특히 선착순 티켓팅 서비스에서는 반드시 검증해야 하는 부분이라고 생각했습니다.

 

현재 제 프로젝트는 Redis 기반 대기열 시스템을 사용하고 있습니다.

 

대기열을 통과하면 아래와 같은 입장권을 발급합니다.

admitted:concert:{concertId}:user:{userId}
예시 : 
admitted:concert:1:user:2

이 key가 존재해야 예약 API 호출이 가능합니다.

즉,

입장권은 반드시 1번만 사용 가능해야 합니다.

그런데 문득 이런 생각이 들었습니다.

"동일 사용자가 동시에 여러 번 요청하면 정말 1번만 예약될까?"

그래서 직접 테스트해봤습니다.


1️⃣ 테스트 목표

이번 테스트에서 검증하고 싶었던 건 3가지였습니다.

👉 동일 사용자 중복 예약 방지

50번 동시에 요청해도 예약은 1건만 생성되어야 합니다.

👉admitted 없는 요청 차단

입장권이 없으면 예약 자체가 실패해야 합니다.

👉 booked_count 정합성 유지

예약 1건이면 booked_count도 정확히 1 증가해야 합니다.


2️⃣ 테스트 환경

  • Backend : Spring Boot
  • DB : MySQL
  • Queue : Redis
  • 테스트 도구 : Apache JMeter

테스트 API

POST /api/concerts/{concertId}/booking

3️⃣ 테스트 전 데이터 초기화

기존 데이터를 먼저 제거했습니다.

delete from booking 
where concert_id = 1 
and user_id = 2;

예약 수 초기화

update concert 
set booked_count = 0 
where id = 1;

4️⃣ Redis 입장권 발급

Redis에 입장권을 단 1개만 발급했습니다.

SETEX admitted:concert:1:user:2 600 1

의미:

  • concertId = 1
  • userId = 2
  • TTL 600초

즉,

예약 가능 권한은 딱 1개만 존재하는 상태입니다.


5️⃣ 단일 요청 테스트

먼저 Postman으로 정상 동작 여부를 확인했습니다.

POST /api/concerts/1/booking

결과

200 OK

DB 확인 결과

  • booking 1건 생성
  • booked_count 1 증가

정상 동작 확인 완료


6️⃣ JMeter 동시 요청 테스트

이제 핵심 테스트입니다.

Apache JMeter 설정

  • Thread : 50
  • Ramp-up : 1초
  • Loop Count : 1
  • Synchronizing Timer : 50

즉,

동일 사용자가 동시에 50번 예약 요청을 보내는 상황

을 만들었습니다.

테스트 직전 다시 admitted를 발급했습니다.

SETEX admitted:concert:1:user:2 600 1

7️⃣ 테스트 결과

총 요청 수

50건

성공

1건

실패

49건

실패 응답

{
  "message": "입장 권한이 없습니다. (입장권이 없거나 만료/이미 사용됨)",
  "status": 409
}

처음 결과를 봤을 때 오히려 안심했습니다.

제가 원했던 결과였기 때문입니다.


8️⃣ DB 검증

예약 개수 확인

select count(*)
from booking
where concert_id = 1
and user_id = 2;

결과

1

booked_count 확인

select booked_count
from concert
where id = 1;

결과

1

즉,

  • 중복 예약 없음
  • booked_count 정합성 유지
  • 초과 예약 없음

모두 확인했습니다.


9️⃣ 왜 이런 결과가 나왔을까?

예약 로직은 다음 흐름으로 동작합니다.

admitted 조회
→ admitted 삭제
→ 예약 생성

첫 번째 요청만

admitted 존재 → 성공

나머지 요청은

admitted 없음 → 실패

결과적으로 Redis 입장권이 1회성 토큰처럼 동작하고 있었습니다.


🔟 이번 테스트에서 배운 점

처음에는 Redis를 단순한 대기열 저장소라고 생각했습니다.

하지만 실제로 테스트해보니 Redis는

  • 대기열 관리
  • 중복 예약 방지
  • 데이터 정합성 보호

역할까지 수행하고 있었습니다.

그리고 무엇보다

"잘 될 것 같아"

가 아니라

실제로 동시 요청 테스트로 검증했다

는 점이 가장 의미 있었습니다.

'프로젝트 > 공연 티켓팅 프로젝트' 카테고리의 다른 글

🎟️ Docker-compose up 한 번으로 실행되는 백엔드 만들기  (1) 2026.05.18
🎟️ MySQL 인덱스 실험: 예약 만료 배치 쿼리 성능 개선 (10만 건 실험)  (1) 2026.05.13
🎟️ 결제 API는 정말 중복 결제를 막을 수 있을까?  (1) 2026.04.27
🎟️ 예약 API 동시성 테스트 (다중 사용자 경쟁) 결과 보고  (1) 2026.04.27
🎟️ 선착순 강의에서 공연 티켓팅으로 확장한 이유  (2) 2026.04.17
'프로젝트/공연 티켓팅 프로젝트' 카테고리의 다른 글
  • 🎟️ MySQL 인덱스 실험: 예약 만료 배치 쿼리 성능 개선 (10만 건 실험)
  • 🎟️ 결제 API는 정말 중복 결제를 막을 수 있을까?
  • 🎟️ 예약 API 동시성 테스트 (다중 사용자 경쟁) 결과 보고
  • 🎟️ 선착순 강의에서 공연 티켓팅으로 확장한 이유
hak0622
hak0622
개발하면서 “이게 뭐지?”라는 순간마다 궁금한 점을 바탕으로 정리한 개발 블로그입니다.
  • hak0622
    궁금한 개발 이야기 Why?
    hak0622
  • 전체
    오늘
    어제
    • 분류 전체보기 (81)
      • 공부 (36)
        • 1. 자바 ORM 표준 JPA 프로그래밍 - 기본.. (35)
        • 시험 (1)
      • 프로젝트 (45)
        • 스프링 부트 3 백엔드 개발자 되기 Blog + .. (35)
        • 공연 티켓팅 프로젝트 (10)
  • 인기 글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
hak0622
🎟️ Redis 입장권 기반 예약 시스템은 정말 중복 예약을 막을까?
상단으로

티스토리툴바