Mutex: 웹 개발에서의 동시성 제어 이해 및 활용
이번 글에서는 웹 애플리케이션에서 자주 부딪히는 동시성 제어 문제를 해결하기 위해 사용하는 Mutex의 개념과 활용 방안을 살펴보려고 합니다. 먼저 학습 목표를 정리하고, 실제 사례를 통해 왜 동시성 제어가 필요한지 이해한 뒤, Java/Spring 환경 예제와 함께 다뤄보겠습니다.
1. 학습 목표
- Mutex의 기본 개념 이해
- 웹 개발 환경에서 동시성 제어가 필요한 이유 파악
- 비관적 락과 낙관적 락의 이해
2. 동시성 제어가 필요한 이유
웹 애플리케이션은 다수의 사용자 요청을 동시에 처리합니다.
이 과정에서 race condition이 발생하면, 예컨대 재고가 1개 남았음에도 두 건의 주문이 동시에 처리되어 재고가 음수로 떨어질 수 있습니다.
실제 쇼핑몰에서 재고 이중 주문 문제가 발생하면 서비스 신뢰도가 크게 떨어지므로, 이를 예방하기 위해 동시성 제어는 필수적입니다.
3. Mutex
3.1. 개념
Mutex(Mutual Exclusion)
한 번에 하나의 스레드만 공유 자원(Critical Section)에 접근하도록 보장하는 락
3.2. 데드락(교착상태)
-
정의
둘 이상의 스레드가 서로 다른 락을 획득한 상태에서, 상대가 가진 락을 얻기 위해 무한 대기하는 상황 -
예시 시나리오
- A 스레드가 A 락 획득
- B 스레드가 B 락 획득
- A 스레드는 A 락을, B 스레드는 B 락를 기다리며 교착
-
예방 기법
- 락 순서 일관화: 모든 스레드가 동일한 순서로 락 획득
- 타임아웃: 일정 시간 내 획득 실패 시 롤백 또는 재시도
- 알고리즘:데드락을 해소하기 위한 여러 알고리즘 존재
4. 웹 개발에서의 Mutex 활용
4.1. 비관적 락 (Pessimistic Lock)
- 개념
데이터 충돌 가능성이 높다고 보고, DB 수준에서 레코드를 즉시 잠금@Transactional public void orderProduct(Long productId, int qty) { // DB 레코드에 즉시 쓰기 락 Product p = em.find(Product.class, productId, LockModeType.PESSIMISTIC_WRITE); if (p.getStock() < qty) { throw new SoldOutException(); } p.decreaseStock(qty); }
4.2. 낙관적 락 (Optimistic Lock)
-
개념
충돌 가능성이 낮다고 가정하고, 데이터를 읽은 시점과 커밋 시점의 버전(version) 정보를 비교하여 동시성 충돌을 검증합니다.
충돌 시OptimisticLockException
이 발생하며, 이를 잡아 재시도 로직을 구현할 수 있습니다. -
엔티티 정의 예시
@Entity public class Product { @Id private Long id; private int stock; @Version private Long version; // 버전 필드 // getters/setters, decreaseStock() 등 }
-
서비스 메서드 예시
@Transactional public void orderProduct(Long productId, int qty) { // 1) 데이터 조회 Product p = repo.findById(productId) .orElseThrow(() -> new EntityNotFoundException("상품 없음")); // 2) 재고 검증 if (p.getStock() < qty) { throw new SoldOutException("재고 부족"); } // 3) 재고 차감 p.decreaseStock(qty); // 4) 커밋 시점에 version 검사 → 충돌 시 OptimisticLockException 발생 }
5. 결론
-
Mutex의 역할
- 한 번에 하나의 스레드만 공유 자원에 접근하도록 보장해 데이터 정합성을 확보합니다.
- 데드락이 발생하지 않도록, 락 순서 일관화·타임아웃 등으로 예방해야 합니다.
-
비관적 락 vs 낙관적 락
- 비관적 락(Pessimistic Lock): 충돌 가능성이 높을 때 DB 레코드를 즉시 잠가 안전하지만 DB 성능 저하
- 낙관적 락(Optimistic Lock): 충돌 빈도가 낮을 때 버전 검증으로 가볍게 처리하되, 충돌 시 재시도 로직 필요
-
적용 전략
- 트래픽·충돌 빈도에 따라 락 방식을 선택
- 분산 환경에서는 Redis 기반 분산 락 도입 고려
- 성능과 가용성 사이 균형을 위해 필요한 곳에만 락을 최소화하여 적용
이상입니다. 감사합니다.