안녕하세요! 이번 프로젝트는
"수만 명의 사용자가 동시에 접속하는 티켓팅 환경에서 어떻게 시스템을 안정적으로 유지할 수 있을까?"
라는 질문에서 시작되었습니다.
단순히 기능을 만드는 것에 그치지 않고, 일부러 시스템을 박살(?) 내보고 하나씩 고쳐나가는 과정을 통해 고가용성 아키텍처를 구축해 나가는 과정을 기록해보려 합니다.
시작하겠습니다 !!

[Part 1] 대규모 트래픽을 견디는 티켓 예매 시스템: 환경 구축과 첫 번째 설계
1. 기술 스택 선정: 왜 이 도구들을 선택했나?
- Java 21 (LTS): 최신 장기 지원 버전으로, 향후 부하 테스트 시 성능 최적화를 고려해 선택했습니다.
- Spring Boot 3.2.2: Redisson 등 외부 라이브러리와의 안정적인 호환성을 고려하여 가장 안정적인 버전을 선택했습니다.
- PostgreSQL: 실무와 유사한 환경을 위해 H2(In-Memory) 대신 선택했습니다.
- Docker & Docker Compose: 인프라를 코드로 관리하고, 서버 확장 시나리오를 쉽게 재현하기 위해 도입했습니다.
- Thymeleaf: 빠르게 프로토타입을 확인하기 위해 서버 사이드 렌더링을 선택했습니다.
2. 데이터베이스 연동: H2에서 PostgreSQL로
처음에는 간편한 H2 데이터베이스로 시작했지만, 실제 부하 테스트를 위해서는 물리적인 데이터베이스 환경이 필요했습니다. Docker를 사용하여 로컬 환경에서도 격리된 DB를 운영하도록 설정했습니다.
docker-compose.yml
애플리케이션과 DB를 하나의 네트워크로 묶어 관리합니다. depends_on 설정을 통해 DB가 먼저 뜬 후 앱이 실행되도록 구성했습니다.
services:
app:
build: .
environment:
- SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/ticketdb
depends_on:
- db
db:
image: postgres:16
environment:
POSTGRES_DB: ticketdb
3. 핵심 기능 구현: 회원가입, 로그인, 그리고 예매
🔒 보안이 생명: Spring Security (Session vs JWT)
초기 아키텍처에서는 단일 서버 환경에 최적화되어 있고 구현이 직관적인 세션(Session) 기반 인증을 선택했습니다.
물론 최근에는 AccessToken과 RefreshToken을 사용하는 JWT 방식이 대중적으로 사용되지만, 이번 프로젝트의 핵심은 "시스템의 진화 과정"을 보여주는 것입니다. 따라서 다음과 같은 로드맵을 계획하고 있습니다.
- 현재: 단일 서버이므로 별도의 인프라 없이 세션 방식으로 빠르게 구축.
- 미래: 트래픽 증가로 인해 Nginx를 앞단에 두고 서버를 여러 대로 늘릴(Scale-out) 예정. 이때 발생하는 세션 불일치 문제를 직접 겪어보고, 이를 해결하는 과정을 다룰 예정입니다.
기본적인 보안 기능은 다음과 같이 구현했습니다.
- 비밀번호 암호화:
BCryptPasswordEncoder를 사용하여 DB에 비밀번호가 평문으로 저장되지 않도록 했습니다. - 이메일 중복 체크: 회원가입 시 중복된 이메일 가입을 원천 차단했습니다.
🎟️ 티켓 예매 로직
현재는 가장 기본적인 형태의 예매 로직을 구현했습니다.
- 유저와 티켓을 조회한다.
- 재고(Stock)를 1 감소시킨다.
- 예약 정보를 저장한다.
@Transactional
public Long reserve(Long userId, Long ticketId) {
Ticket ticket = ticketRepository.findById(ticketId).orElseThrow();
ticket.decreaseStock(); // 현재는 단순 감소 로직
return reservationRepository.save(new Reservation(user, ticket)).getId();
}
4. 마치며: 하지만 이 코드는 "박살날 예정"입니다.
현재 구현된 예매 로직에는 치명적인 약점이 있습니다. "동시에 여러 명이 예매 버튼을 누른다면?"에 대한 대비가 전혀 되어 있지 않기 때문입니다.
- 문제점: 재고가 10개인데 50명이 동시에 성공하는 '초과 판매' 이슈가 발생할 수 있습니다.
- 다음 포스팅 계획: JMeter를 이용해 실제로 재고가 꼬이는 현상을 목격하고, 이를 DB Lock과 Redis 분산 락으로 해결해 나가는 과정을 공유하겠습니다.
감사합니다.

다음 포스팅
https://changbroblog.tistory.com/240
위기: "재고가 이상해요..." - 동시성 이슈와의 전쟁
전 포스팅에서 구축한 시스템으로 야심 차게 부하 테스트를 진행했습니다. JMeter를 통해 '2026 싸이 흠뻑쇼 - 서울' 공연을 300명이 동시에 예매하기를 누른다고 가정하고 테스트를 진행하겠습니다
changbroblog.tistory.com
'Project > 티켓 예매 시스템(대규모 트래픽 테스트)' 카테고리의 다른 글
| 확장: "로그인이 자꾸 풀려요" - Scale-out과 세션 정합성 (0) | 2026.02.05 |
|---|---|
| 위기: "재고가 이상해요..." - 동시성 이슈와의 전쟁 (1) | 2026.02.02 |