대규모 트래픽 상황(신규 게임 서버 오픈, 한정판 구매, 이벤트 페이지 등)에서
사용자 요청을 선착순 대기열로 제어하고 순번에 따라 입장을 허용하는 Spring Boot 예제입니다.
Live DEMO 시나리오
/waiting-room?queue=default&user_id=101&redirect_url=/home
접속- 대기 순번 표시 → 스케줄러가 허용되면 자동으로
/home
으로 이동- 백오피스(API 또는 스케줄러)가 3명씩 입장을 허용
┌──────────────┐ POST /queue ┌───────────────┐
│ Client │ ───────── register ─────────▶ │ Redis ZSET │
│ (Browser) │ │ wait:<queue> │
└──────────────┘ └───────────────┘
▲ │`
│ GET /rank │ ZPOP
│ GET /allowed ▼
┌──────────────┐ allow (Scheduler/API) ┌───────────────┐
│ Waiting room │ ◀────────────────────────────► │ Redis ZSET │
│ (Thymeleaf) │ │ proceed:<q.> │
└──────────────┘ └───────────────┘
단계 | 설명 |
---|---|
① 대기열 등록POST /api/v1/queue |
Redis users:queue:{queue}:wait (ZSET)에 가입 시각을 score로 삽입 & 내 순번 반환 |
② 대기 페이지/waiting-room |
순번을 주기적으로 조회하여(REST) 입장 허용 시 redirect_url 로 이동 |
③ 입장 허용/queue/allow 또는 스케줄러 |
wait ZSET에서 N명 ZPOP → proceed ZSET으로 이동, 동시에 토큰 발급 |
④ 토큰 검증/queue/allowed |
사용자는 /touch 로 토큰 쿠키를 발급받고, 입장 시 토큰으로 최종 검증 |
✔️ ZSET을 사용하므로 O(log N) 정렬·조회, Reactive Redis로 논블로킹 처리
✔️@Scheduled
동작 여부는application.yaml > scheduler.enabled
로 on/off
user-queue-system/
├── build.gradle # 멀티 모듈 루트 (Gradle 8.x)
├── settings.gradle # include "x-flow"
└── x-flow/ # API & Waiting‑Room
├── src/main/java/com/bmcho/xflow
│ ├── controller # REST + Thymeleaf Controller
│ ├── service # Queue 로직 (Redis ZSET)
│ ├── dto # API 응답 VO (Record)
│ └── exception # 공통 오류 처리
├── src/main/resources
│ ├── templates/ # waiting-room.html
│ └── application.yaml
└── build.gradle
추가 폴더 x-website/ 는 단순 Spring MVC 샘플 페이지(독립 프로젝트)로,
실동작과는 무관합니다.
범주 | 사용 기술 |
---|---|
Core | Spring Boot 3.5, Spring WebFlux, Reactive Redis |
DB | Redis 7 (ZSET, SCAN) |
View | Thymeleaf 3 |
Build | Gradle 8, Java 17 Toolchain |
Test | JUnit 5, embedded‑redis (메모리 Redis) |
docker run -d --name redis -p 6379:6379 redis:7-alpine
cd user-queue-system
./gradlew :x-flow:bootRun
# 기본 포트 9010, profile=local
# ① 대기열 등록 (user_id=100)
curl -X POST "http://localhost:9010/api/v1/queue?queue=default&user_id=100"
# → {"rank":1}
# ② 3명 허용
curl -X POST "http://localhost:9010/api/v1/queue/allow?queue=default&count=3"
# → {"requestCount":3,"allowedCount":1}
# ③ 순번 조회
curl "http://localhost:9010/api/v1/queue/rank?queue=default&user_id=100"
TIP 스케줄러 자동 허용을 사용하려면
application.yaml
의
scheduler.enabled: true
로 두고 주기·허용 인원(count)을UserQueueService#scheduleAllowUser
에서 조정하세요.
Method | URI | Query String | 설명 |
---|---|---|---|
POST |
/api/v1/queue |
queue , user_id |
대기열 등록 & 순번 반환 |
POST |
/api/v1/queue/allow |
queue , count |
대기열에서 N명 허용 |
GET |
/api/v1/queue/rank |
queue , user_id |
현재 순번 조회 |
GET |
/api/v1/queue/touch |
queue , user_id |
토큰 쿠키 발급 |
GET |
/api/v1/queue/allowed |
queue , user_id , token |
입장 가능 여부 |
GET |
/waiting-room |
queue , user_id , redirect_url |
대기 페이지(HTML) |
-
토큰 기반 입장 검증
동일 사용자가 브라우저 새로고침만으로 대기열을 건너뛰지 못하도록
SHA‑256(user-queue-{queue}-{userId})
기반 토큰을 쿠키로 발급·검증합니다. -
멀티 대기열 지원
Redis 키에{queue}
변수를 사용 (users:queue:{queue}:wait
)
→ 서비스 인스턴스 1개로 여러 이벤트 대기열 동시 운영 가능. -
Reactive Non‑Blocking
ReactiveRedisTemplate
·Project Reactor로 트래픽 피크 상황에서도
스레드 풀 증설 없이 적은 리소스로 처리합니다. -
Embedded Redis 테스트
CI나 로컬 테스트 시 외부 Redis 의존성 없이 단위 테스트를 실행합니다.
항목 | 보강 내용 |
---|---|
보안 | 토큰 위·변조 방지(HMAC 서명), HTTPS, CORS |
대기열 공정성 | IP/계정당 중복 등록 방지, BOT 감지(Recaptcha) |
모니터링 | 허용률·대기 인원·실패률 Prometheus / Grafana 지표 |
백오피스 | 관리자 대시보드(WebSocket)로 실시간 제어 |
고가용성 | Redis Cluster / Sentinel, 앱 다중 인스턴스 |
실 서비스 적용 시에는 인증, 보안, 장애 복구, 데이터 일관성 등을 추가로 고려해야 합니다.