추가 해결 사항
💡 문제 상황
- Redisson 분산 락 적용 중 트랜잭션 커밋 순서 문제를 해결하는 과정에서 다수의 동시 요청이 하나의 재고 락에 몰리면서 일부 요청이 tryLock의 대기 시간 안에 락을 획득하지 못하는 상황이 발생했고, 이 요청들이 락 획득 실패 예외로 처리되어 동시성 테스트 통과가 이뤄지지 않는 문제가 발생했다.
💡 문제 증상
- 현재 tryLock(WAIT_TIME_SECONDS, LEASE_TIME_SECONDS, TimeUnit.SECONDS)에서 WAIT_TIME_SECONDS 동안 락 획득을 기다리지만, 그 시간 안에 락을 얻지 못하면 false를 반환한다.
- 이를 곧바로 STOCK_LOCK_TIMEOUT 예외로 변환했기 때문에 일부 요청이 재시도 없이 실패 처리되어 동시성 테스트가 통과하지 못했다.
package com.hubEleven.stock.infrastructure.lock;
@Component
@RequiredArgsConstructor
public class RedissonStockLockManager implements StockLockManager {
private static final long WAIT_TIME_SECONDS = 3L;
private static final long LEASE_TIME_SECONDS = 5L;
private final RedissonClient redissonClient;
@Override
public <T> T executeWithLock(String lockKey, Supplier<T> supplier) {
RLock lock = redissonClient.getLock(lockKey);
boolean locked = false;
try {
locked = lock.tryLock(WAIT_TIME_SECONDS, LEASE_TIME_SECONDS, TimeUnit.SECONDS);
if (!locked) {
throw new GlobalException(STOCK_LOCK_TIMEOUT);
}
return supplier.get();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new GlobalException(STOCK_LOCK_TIMEOUT);
} finally {
if (locked && lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
}
해결 방안 검토
💡 해결 방안
- 대략적으로 해결 가능한 락 획득 대기 시간 초과 시 예외 처리 정책을 요약해보면 아래와 같다.
| 정책 | 요약 | 세부 내용 | 장점 | 단점 |
| A | 너무 오래 기다리는 요청은 실패시킨다 | - 트래픽 폭주 시 일부 요청은 빠르게 실패시키고 재시도를 유도한다. - WAIT_TIME을 제한적으로 설정 - 락 획득 실패 시 409 CONFLICT 반환 - 클라이언트가 재시도하거나 사용자에게 안내 |
- 서버가 오래 붙잡히지 않음 - 트래픽 폭주 시 빠르게 실패 처리 가능 |
- 사용자 요청 일부가 실패할 수 있음 - 클라이언트 재시도 설계가 필요함 |
| B | 서버 내부에서 재시도 처리 | 1. 락 획득 시도 2. 실패 3. 짧게 대기 4. 다시 시도 5. 몇 회 실패하면 최종 실패 |
- 순간적인 경합은 흡수 가능 - 사용자 실패율 감소 |
- 응답 시간이 길어질 수 있음 - 재시도 폭주가 생기면 서버 부하 증가 - 재시도 횟수/간격 정책이 필요함 |
| C | 주문 요청을 큐로 보내 순차 처리 | - Kafka, RabbitMQ 같은 큐를 사용 - 주문 요청 → 큐에 적재 → 재고 감소 consumer가 순서대로 처리 |
- 대량 트래픽을 안정적으로 흡수 가능 - 재고 감소를 순차 처리하기 쉬움 - 락 경합 감소 |
- 구현 복잡도 증가 - 비동기 처리 구조 필요 - 사용자에게 즉시 확정 응답을 주기 어려울 수 있음 |
해결 방법
💡 해결 방법 : 락 획득 실패 시 제한적 재시도 후 명시적인 예외를 반환
최대 3번 반복:
tryLock 시도
성공하면 supplier 실행
실패하면 짧게 대기 후 재시도
3번 모두 실패:
STOCK_LOCK_TIMEOUT 예외
- 락 획득 실패를 곧바로 비즈니스 실패로 처리하면 순간적인 트래픽 집중 상황에서 정상 처리 가능한 요청까지 실패할 수 있다고 판단했다.
- 이에 제한된 횟수의 재시도를 통해 일시적인 락 경합을 완화하고, 재시도 후에도 락을 획득하지 못한 경우에는 STOCK_LOCK_TIMEOUT 예외를 명시적으로 반환하여 클라이언트 또는 상위 계층에서 재시도 여부를 판단할 수 있도록 설계했다.
Redisson 재시도 구조가 가능한 이유
💡 Redis Pub/Sub 구조
검증
💡 동시성 테스트
1. 테스트 진행 방식
- 동시에 100개의 요청이 같은 상품 재고를 1개씩 감소시키는 테스트를 작성했다.
2. 테스트 통과 결과
- Redisson 분산 락과 트랜잭션 경계 분리 후 테스트가 통과했다.

개선할 사항
- 추후 확작성을 고려하다면, 모든 요청이 순차적으로 처리될 수 있게 Kafka, RabbitMQ 같은 기술을 활용해 재시도 로직을 개선하면 좋을 것 같다.
참고 자료
'Projects > hub-eleven' 카테고리의 다른 글
| [트러블슈팅] Redisson 분산 락 적용 중 트랜잭션 커밋 순서 문제를 해결한 과정 (1) (0) | 2026.06.22 |
|---|---|
| [동시성 처리] 재고 감소 락 추상화 및 Redisson 락 구현 (아키텍처 구조 보완 필요) (0) | 2026.06.02 |
| [동시성 처리] RedissonClient Bean 설정 클래스 추가 (2) (리소스 보완 필요) (0) | 2026.05.28 |
| [동시성 처리] RedissonClient Bean 설정 클래스 추가 (1) (0) | 2026.05.27 |
| [동시성 처리] 동시성 문제 (Race Conditon) 해결하기 (0) | 2026.05.11 |