< 프로세스 >
유저 등록 → 대기열 진입( 대기열 토큰 발급 ) → 예약 → 콘서트 결제 or 잔액 충전 및 조회 → 완료
여러 스레드가 동시에 공유 자원에 접근할 때 발생하는 문제이다. 이는 데이터의 일관성을 해칠 수 있다.
EX ) 은행 계좌에 두 사람이 동시에 돈을 인출 → 한 사람만 가능해야 하는데 동시 접근 시 둘 다 조회가 가능하게 되는 상황 발생 → 두 명다 인출 → 내 돈 GG..
시나리오 1 )
시나리오 2 )
데이터 접근 시 락을 사용하지 않고, 업데이트 시점에 충돌을 감지하여 처리한다. 주로 엔티티에 @Version 필드를 추가하여 구현한다.
장점
높은 성능: 락을 사용하지 않으므로 트랜잭션 간의 대기가 발생하지 않는다.
교착 상태 방지: 락을 사용하지 않으므로 교착 상태 문제가 발생하지 않는다.
단점
충돌 시 재시도 필요: 업데이트 시점에 충돌이 발생하면 재시도 로직이 필요하다.
복잡한 오류 처리: 충돌 발생 시 예외 처리를 별도로 구현해야 하다.
구현 복잡도: 중간
성능(시간): 높음
효율성: 중간 (충돌 시 재시도 필요)
한계: 충돌 발생 시 처리 복잡성 증가
데이터에 접근할 때 즉시 락을 걸어 다른 트랜잭션이 해당 데이터에 접근하거나 수정하지 못하도록 방지. 주로 SELECT ... FOR UPDATE 구문이나 JPA의 @Lock(LockModeType.PESSIMISTIC_WRITE)를 사용
장점
데이터 일관성 보장: 충돌 가능성이 높은 상황에서 데이터의 일관성을 강력하게 보장할 수 있다.
단순한 구현: JPA와 같은 ORM 프레임워크를 이용하면 쉽게 구현할 수 있다.
단점
성능 저하: 락을 오래 유지할 경우 다른 트랜잭션이 대기하게 되어 시스템 전체의 성능이 저하될 수 있다.
교착 상태(Deadlock) 위험: 여러 트랜잭션이 서로 락을 기다리며 교착 상태에 빠질 수 있다.
구현 복잡도: 중간
성능(시간): 낮음 (락으로 인한 대기 발생)
효율성: 높음 (데이터 일관성 보장)
한계: 교착 상태 발생 가능성, 성능 저하
트랜잭션 격리 수준 제어
Redis 분산 락
Redis와 같은 인메모리 데이터 저장소를 이용하여 분산 환경에서 락을 관리. 예를 들어, Redisson 라이브러리를 사용하여 구현할 수 있다.
장점
분산 환경 지원: 여러 인스턴스 간에 락을 공유할 수 있어 분산 시스템에 적합.
높은 성능: 인메모리 저장소의 특성상 빠른 락 획득과 해제가 가능.
단점
추가 인프라 필요: Redis 서버와 같은 추가적인 인프라가 필요.
복잡한 설정: 락 관리와 관련된 설정이 복잡할 수 있다.
구현 복잡도: 높음
성능(시간): 높음
효율성: 높음
한계: 추가 인프라 필요, 설정 복잡성
메시지 큐를 사용하여 예약 요청을 순차적으로 처리. 예를 들어, Kafka, RabbitMQ 등을 활용할 수 있다.
장점
확장성: 메시지 큐를 통해 요청을 비동기적으로 처리하므로 높은 확장성을 가질 수 있다.
신뢰성: 메시지 큐는 메시지의 내구성과 신뢰성을 보장.
단점
복잡성: 메시지 큐 시스템의 도입과 관리가 복잡할 수 있다.
지연 시간: 비동기 처리로 인해 즉각적인 응답이 어려울 수 있다.
구현 복잡도: 높음
성능(시간): 중간 (메시지 큐의 처리 속도에 의존)
효율성: 높음 (비동기 처리로 시스템 부하 분산)
한계: 복잡한 시스템 아키텍처, 지연 시간
"한 좌석에 여러 사용자가 동시에 접근" 하는 경우, 비관적 락을 사용하여 동시성 문제를 해결하고자 했다. 그 이유는 서비스 자체가 좌석이 있는 콘서트 예약인데 그렇다면 매우 빈번하게 여러 유저들이 같은 좌석에 접근할 것이라고 생각했기 때문이다. 비관적 락을 사용해 동시 접근을 효과적으로 막을 수 있다고 생각했다.
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("SELECT s FROM Seat s WHERE s.seatNumber = :seatNumber AND s.concertEvent.id = :eventId")
Optional<Seat> findSeatForUpdate(@Param("seatNumber") String seatNumber,
@Param("eventId") Long eventId);
한 사용자가 여러 좌석을 예약하는 경우는 좌석 예약과 다르게 빈번하게 일어나는 경우가 아니다. 때문에 위에서 조사한 것과 같이 낙관적 락을 사용하여 성능적으로 더 좋은 결과를 보여줄 수 있다고 생각하여 해당 경우는 낙관적 락을 도입할 예정이다.