개요
타임딜 오픈 순간처럼 동일 상품 주문이 한 번에 몰리는 상황에서는 락 전략에 따라 재고 정합성과 처리량이 크게 달라집니다. 이 프로젝트에서는 비관적 락, 낙관적 락, Redis 분산 락을 같은 부하 조건에서 비교하고, 캐시와 Resilience4j까지 붙여 운영 패턴도 함께 검증했습니다. 단순히 락을 구현하는 데서 끝내지 않고 어떤 전략이 어떤 경합 상황에서 유리한지 숫자로 판단할 수 있게 만든 프로젝트입니다.
검증 목표
- ›동시성 제어 전략(비관적/낙관적/분산 락)의 차이를 실제 부하로 비교
- ›장애 상황(DB/Redis 다운)에서 시스템이 어떻게 동작하는지 검증
- ›캐시, Rate Limit, Circuit Breaker 조합이 운영 병목 완화에 어떻게 기여하는지 검증
동시성 제어 비교 (200 VU 스파이크)
- ›비관적 락: 162 RPS, p95 935ms, 성공률 100%, 6,594건 처리
- ›낙관적 락: 144.7 RPS, p95 1,170ms, 실패율 23.3% (version 충돌)
- ›분산 락(Redis): 132 RPS, p95 1,770ms, 실패율 42.6% (락 획득 실패)
- ›결론: 고경합 상황에서는 비관적 락이 처리량과 안정성 모두 우수
기술적 구현
- ›order.lock-strategy 설정으로 3가지 전략 런타임 전환
- ›Caffeine 캐시(10K 엔트리, 10분 TTL)로 조회 p95 70% 개선
- ›Resilience4j Rate Limiter(100 req/s) + Circuit Breaker(50% 임계치)
- ›Prometheus + Grafana 대시보드로 RPS·레이턴시·JVM 메모리 실시간 모니터링
- ›Testcontainers로 MySQL/Redis 통합 테스트 환경 구성
아키텍처
전체 아키텍처▼
ERD
전체 ERD▼
시퀀스 다이어그램
문제 원인
- 01타임딜 오픈 시점에 동일 상품에 200명 동시 주문이 몰리면서 재고 정합성이 깨질 수 있었습니다.
- 02낙관적 락만 사용 시 version 충돌로 23.3% 실패율이 발생했습니다.
- 03상품 조회 부하가 커서 p95 38.8ms로 응답이 느렸습니다.
- 04메트릭 없이 병목을 확인하기 어려웠고, DB/Redis 장애 시 동작 검증이 필요했습니다.
해결 과정
- 01비관적·낙관적·분산 락(Redis SET NX PX, 5초 TTL) 세 가지 전략을 구현하고 order.lock-strategy로 전환 가능하게 했습니다.
- 02k6로 동일 조건(0→200 VU, 60초)에서 비교해 비관적 락이 처리량(162 vs 132 RPS)과 성공률(100% vs 57.4%) 모두 우수함을 확인했습니다.
- 03Caffeine 캐시(itemList, items 키, 10분 TTL)와 Resilience4j Rate Limiter(100 req/s)·Circuit Breaker(10 콜 윈도우, 50% 임계치, 5초 복구)를 적용했습니다.
- 04Prometheus(15초 스크래핑) + Grafana 대시보드를 구성하고, timedeal.order.create 커스텀 메트릭으로 성공/실패별 레이턴시를 추적했습니다.
결과
- 01비관적 락 기준 162 RPS, p95 935ms, 6,594건 주문 성공, 에러율 0%를 달성했습니다.
- 02분산 부하(멀티 상품) 시 247 RPS까지 처리량이 증가했습니다.
- 03캐시 도입으로 상품 조회 p95가 38.8ms → 11.6ms로 70% 개선되었습니다.
- 04Rate Limiter 적용 후 99.87% 성공률을 유지하며 8건만 429로 거부되었습니다.
- 05DB 장애 시 즉시 실패 처리, 복구 후 15초 내 정상화됨을 검증하고 PERF_RESULT.md에 문서화했습니다.