| 지표 | 비관적 락 (AS-IS) | Redis Atomic + 비동기 (TO-BE) | 개선 효과 |
|---|---|---|---|
| 최대 수용 VU | 50 VU | 1,00 VU | 20배 확장성 확보 |
| 요청 수용률 | 38.9% (VU 50) | 99.9%(VU 1000) | 요청 전량 처리 |
| p(95) Latency | 60s+ | 6.17s ~ 7.44s | 가용성 임계치 대폭 증가 |
| 비즈니스 정합성 | 정상 측정 불가 | 초과 발급 0건 | 비즈니스 정합성 100% |
<aside> ✅
VU 1000 환경에서 발생한 0.1%의 미수용 건은 서버 로직 에러가 아닌, Peak 구간 TCP Connection 유실(EOF)로 확인
</aside>
[선택 배경] 비즈니스 신뢰도 확보를 위한 초과 발급 차단
[적용 기술] 데이터베이스 트랜잭션 수준의 배타적 잠금(Exclusive Lock)
PESSIMISTIC_WRITE를 사용하여 데이터 조회 시점부터 수정 권한을 독점
트랜잭션이 종료될 때까지 타 세션의 읽기/쓰기 접근을 차단하여 Race Condition 원천 제거
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("select c from Coupon c where c.id = :id")
Optional<Coupon> findByIdWithLock(Long id);
[발생 문제] DB Lock 경합으로 인한 시스템 전체 가용성 급격히 저하 (전체 요청의 실패율 : 97.79%)
현상: 낮은 동시성(50 VU) 환경에서도 극단적인 실패율(97.79%) 발생
![[지표] 50 VU의 낮은 환경에서도 전체 요청의 97.79%가 실패](attachment:8cc0fc4f-90ae-48d5-bf85-e5cc26ac78d9:%EB%9D%BD_%EA%B2%BD%ED%95%A9.png)
[지표] 50 VU의 낮은 환경에서도 전체 요청의 97.79%가 실패
[원인 1] 단일 쿠폰 Row에 비관적 락이 집중되며 Lock Wait 발생
모든 요청이 동일 쿠폰 Row에 대해 SELECT …FOR UPDATE를 수행하면서 락 해제 전까지 트랜잭션이 대기 상태로 누적되며, Active Session만 증가하고 실제 처리량은 증가하지 않는 상태 발생
![[분석] 비관적 락 경합으로 Lock Wait가 누적되며 Active Session만 증가](attachment:0c7fc136-0d4f-4e75-a0d2-12a840dd26dc:MergedImages.png)
[분석] 비관적 락 경합으로 Lock Wait가 누적되며 Active Session만 증가