목차 열기
Redis 구성
Redis는 두 개의 독립적인 인스턴스로 분리하여 운영합니다. 티켓 오픈 시 대기열 트래픽이 폭발해도 인증과 좌석 분산 락 성능에 영향을 주지 않도록 설계했습니다.
인스턴스 분리 구성
공용 Redis :6379 (Gateway / Auth-Guard / Seat / Order-Core)
| Key | Type | 설명 | TTL |
|---|---|---|---|
refresh_token:{jti} | STRING | Refresh Token 저장 (IP/UA 포함) | 설정 가능 (기본 4시간) |
token_blacklist:{jti} | STRING | 로그아웃 토큰 차단 | 남은 Access Token TTL |
user-by-id:{userId} | STRING (JSON) | User DTO 분산 캐시 | 10분 |
auth-me:{userId} | STRING (JSON) | /auth/me 응답 캐시 | 30초 |
seat:booking-options:{m}:{u} | STRING (JSON) | 예매 옵션 (추천/인원수/인접석) | 900초 (15분) |
seat:recommendation:match:{m}:block:{b} | Redisson RLock | 블럭 단위 분산 락 (Watch Dog) | 자동 갱신 |
seat:hold:match:{m}:seat:{s} | Redisson RLock | 좌석 단위 분산 락 | 5초 lease |
seat-groups-response:{m} | STRING (JSON) | 좌석맵 API 응답 캐시 | 5초 |
matches-list-response:{date} | STRING (JSON) | 경기 목록 API 응답 캐시 | 30초 |
rate_limit:{ip}:{ep} | STRING (INCR) | Rate Limiting 카운터 (prod) | 60초 |
Queue 전용 Redis :6380
| Key | Type | 설명 | TTL |
|---|---|---|---|
queue:wait:{matchId} | ZSET | 대기열 사용자 순서 (score = 진입 타임스탬프) | 없음 |
queue:ready:{m}:{u} | STRING | Ready 상태 토큰 payload | 60초 (설정 가능) |
queue:ready:index:{m} | SET | Ready 유저 인덱스 (cleanup용) | 없음 |
queue:expired:{m}:{u} | STRING | 만료 마커 | 300초 |
queue:match | SET | 활성 티켓팅 경기 목록 | 없음 |
queue:precheck:booking-option:{m}:{u} | STRING | PreQueue 검증용 예매 옵션 마커 | 900초 |
인스턴스 분리 이유
| 문제 | 해결 |
|---|---|
| 대기열 폭발 시 Redis 부하 → 인증/락 지연 | Queue 전용 인스턴스 분리로 영향 차단 |
| 블랙리스트 확인 지연 → JWT 검증 병목 | 공용 Redis(Auth/Lock)가 항상 안정적 응답 보장 |
| 좌석 분산 락 실패 → 동시성 이슈 | 대기열 트래픽과 분리되어 락 성공률 보장 |
Redis 활용 전략 정리
1. 캐시 계층 (Caffeine vs Redis)
| 항목 | Caffeine (로컬) | Redis (원격) |
|---|---|---|
| 저장 위치 | JVM 힙 메모리 | 별도 서버 |
| 접근 시간 | < 1μs | 0.5~2ms (+네트워크) |
| 인스턴스 간 공유 | 각자 따로 | 공유됨 (단일 소스) |
| 일관성 | 노드별 달라질 수 있음 | 단일 소스 |
| 적합 데이터 | 불변 (Match, Section, Block) | 변동 가능 (User, 응답) |
2. 분산 락 (Redisson RLock)
SETNX 기반 단순 락에서 Redisson RLock으로 전환했습니다. Watch Dog으로 DB 트랜잭션 지연 시 TTL 자동 갱신, 스레드 ID 기반 소유자 검증, Pub/Sub 기반 효율적 대기 등을 제공합니다.
3. Lua 스크립트 원자 연산 (Phase 4 최적화)
대기열 재진입 시 ZREM + ZADD + ZRANK + ZCARD를 Lua 스크립트로 묶어3 RTT → 1 RTT로 단축했습니다.
-- queue:re-enter atomic script
redis.call('ZREM', KEYS[1], ARGV[1])
redis.call('DEL', KEYS[2])
redis.call('ZADD', KEYS[1], ARGV[2], ARGV[1])
local rank = redis.call('ZRANK', KEYS[1], ARGV[1])
local count = redis.call('ZCARD', KEYS[1])
return {rank, count}PostgreSQL 테이블 소유권
| 서비스 | 소유 테이블 | 비고 |
|---|---|---|
| Auth-Guard | users, user_sns, dev_users, withdrawal_requests | 회원 관리 (AES-GCM 암호화) |
| Seat | seats, blocks, sections, areas, match_seats, seat_holds, price_policies | 좌석/가격 구조 |
| Order-Core | orders, order_seats, payments, cash_receipts, cancellation_fee_policies, inquiries | 주문/결제 (PII 암호화) |
| 공유 (common-core) | matches, clubs, stadiums, onboarding_preferences, onboarding_preferred_blocks, onboarding_viewpoint_priority | 공유 도메인 |