낙관적 락은 데이터에 대한 충돌이 적을 것이라고 가정하고, 별도의 DB 락을 사용하지 않고 버전(version) 값을 통해 동시성 충돌을 감지하는 방식이다.
JPA에서는 @Version 필드를 사용하여 구현할 수 있으며, 데이터를 수정할 때 기존 버전과 현재 버전을 비교하여 값이 다를 경우 OptimisticLockException을 발생시킨다.
즉, 낙관적 락은 충돌을 예방하는 방식이 아니라, 충돌 발생 시 감지하고 처리하는 방식이다.
낙관적 락은 다음과 같은 환경에서 효과적이다.
읽기 비중이 높고, 쓰기 충돌이 적은 서비스
동일 데이터에 대해 동시에 수정 요청이 자주 발생하지 않는 경우
DB 레벨의 락으로 인한 대기(wait)를 최소화하고 싶은 경우
예를 들어:
게시글 조회/수정 시스템
사용자 프로필 수정
통계 데이터 조회
이러한 경우에는 비관적 락보다 낙관적 락이 더 효율적이며, 불필요한 DB Lock을 사용하지 않아 성능 측면에서 유리하다.
낙관적 락에서는 충돌 발생 시 OptimisticLockException이 발생하므로, 이를 처리하기 위한 재시도 로직(Retry)이 필요하다.
1) 재시도 횟수
일반적으로 3~5회 정도로 제한하는 것이 적절하다
무한 재시도는 시스템 부하를 증가시키므로 피해야 한다
2) 재시도 간격 (Backoff)
단순 즉시 재시도보다는 지연(backoff)을 두는 것이 좋다
예:
이를 통해 충돌이 반복되는 상황을 완화할 수 있다
3) 실패 처리 전략
일정 횟수 이상 실패 시:
낙관적 락은 충돌이 적은 환경에서는 효율적이지만, 다음과 같은 상황에서는 오히려 성능 저하를 유발할 수 있다.
예를 들어:
선착순 쿠폰 발급
재고 감소 처리
입찰 시스템
이와 같이 동일 데이터에 대한 동시 수정이 빈번한 경우, 다음과 같은 문제가 발생할 수 있다.
OptimisticLockException 빈번 발생
재시도 로직 반복 실행
DB 요청 증가
전체 처리량 감소
즉, 충돌이 많은 환경에서는 낙관적 락이 오히려 비효율적인 구조가 될 수 있다.
| 구분 | 낙관적 락 | 비관적 락 |
|---|---|---|
| 방식 | 충돌 발생 후 감지 | 충돌 발생 전 차단 |
| DB | Lock 사용하지 않음 | 사용함 |
| 성능 | 읽기 많을 때 유리 | 충돌 많을 때 유리 |
| 적합한 환경 | 조회 위주, 충돌 적음 | 동시 수정 많음 |
낙관적 락은 DB 락 없이 version 값을 통해 충돌을 감지하는 방식으로,
읽기 중심의 서비스에서는 높은 성능을 제공할 수 있다.
하지만 충돌이 빈번한 환경에서는 재시도 로직으로 인해
오히려 성능 저하가 발생할 수 있으므로,
서비스 특성에 따라 비관적 락 또는 분산 락과의 적절한 선택이 필요하다.