대규모 트래픽 상황에서도 **데이터 정합성(Data Integrity)**을 보장하는 콘서트 티켓팅 서비스 백엔드입니다. **동시성 제어(Concurrency Control)**와 자동 예약 취소(Dead Stock Management) 기능을 중점으로 구현했습니다.
- Runtime: Node.js, TypeScript
- Framework: Express.js
- Database: PostgreSQL
- ORM: Prisma
- Cache/Queue: Redis (ioredis)
- Architecture: Layered Architecture (Controller - Service - Repository)
- 문제 상황: 다수의 사용자가 동시에 동일한 좌석(
Seat)을 예매 시도 시 발생하는 중복 예약(Overbooking) 현상 방지. - 해결: Prisma Transaction과 PostgreSQL의
SELECT ... FOR UPDATE를 활용한 비관적 락(Pessimistic Lock) 적용. - 검증: 자체 제작한 테스트 스크립트로 100개의 동시 요청 시뮬레이션 결과, 단 1건만 성공하고 99건은 차단됨을 검증.
- 문제 상황: 사용자가 좌석을 선점(
RESERVED)한 후 결제를 진행하지 않아 발생하는 유령 좌석(Dead Stock) 문제. - 해결: Redis
Sorted Set을 활용한 지연 큐(Delayed Queue) 구현. - 로직: 예약 시점 + 10초(테스트용)를 Score로 등록 후, 1초 단위 스케줄러가 만료된 좌석을 감지하여 DB 상태를 롤백(
AVAILABLE)하고 대기열에서 삭제.
src/
├── config/ # Prisma, Redis 클라이언트 설정
├── controllers/ # Request/Response 처리
├── services/ # 비즈니스 로직 (트랜잭션, 락, Redis 큐)
├── routes/ # API 라우팅 정의
├── jobs/ # 스케줄러 (자동 취소 로직)
└── app.ts # 앱 진입점이 프로젝트를 로컬 환경에서 실행하기 위한 단계별 가이드입니다.
이 프로젝트를 실행하려면 아래 프로그램들이 사전에 설치되어 있어야 합니다.
- Node.js (v18 이상 권장)
- PostgreSQL (데이터베이스)
- Redis (큐 관리용)
프로젝트 패키지를 설치합니다.
# 패키지 설치
npm install프로젝트 루트에 .env 파일을 생성하고 데이터베이스 URL을 설정해야 합니다.
DATABASE_URL="postgresql://USER:PASSWORD@localhost:5432/mydb?schema=public"
Prisma 스키마를 DB에 동기화하고, Prisma Client를 생성합니다.
# DB 스키마 동기화
npx prisma db push
# Prisma Client 생성
npx prisma generate테스트를 위해 유저 100명과 테스트용 좌석(seat_abc_123) 데이터를 생성합니다. (이 과정을 건너뛰면 테스트가 작동하지 않습니다.)
node prisma/seed.js서버를 실행합니다. (기본 포트: 3000)
npx ts-node src/app.ts🧪 Test Scenarios (검증 방법) 시나리오 1: 동시성 제어 테스트 (Concurrency Test) 100명의 유저가 동시에 하나의 좌석(seat_abc_123) 예약을 시도하는 상황을 시뮬레이션합니다.
목표: 단 1명만 성공하고, 나머지 99명은 실패(409 Conflict)해야 함.
# 서버가 켜진 상태에서, 별도의 터미널을 열고 실행하세요
npx ts-node src/concurrency-test.ts[예상 결과]
✅ 성공한 요청 수: 1 ❌ 실패한 요청 수: 99 🎉 테스트 통과! 동시성 제어가 완벽하게 동작합니다.
시나리오 2: 자동 취소 테스트 (Redis Queue) 예약 후 결제를 하지 않은 상황을 가정하여, 10초 뒤 좌석이 자동 회수되는지 확인합니다.
-
서버 실행(npx ts-node src/app.ts)
-
예약 요청 전송 (cURL 사용)
curl -X POST http://localhost:3000/reservations \
-H "Content-Type: application/json" \
-d '{"seatId": "seat_abc_123", "userId": "user_0"}'- 서버 로그 확인
-
🎫 예약 성공! 메시지가 즉시 출력됩니다.
-
정확히 10초 후, ✅ 좌석 자동 취소 완료! 메시지가 출력되면 성공입니다.