2024.08.09.금.TIL 내일배움캠프 81일차 <최종프로젝트Day17>

김기남·2024년 8월 9일
post-thumbnail

안녕하세요, 오늘은 최종프로젝트에서 구현중인 동시성제어 에 대해 정리해보았습니다.

멀티 스레드 환경에서 레이스 컨디션이 발생하는 이유

레이스 컨디션이란 여러 개의 프로세스가 공유 자원에 동시 접근할 때 실행 순서에 따라 결과값이 달라질 수 있는 현상을 말합니다.

예상 작업 순서
멀티 스레드로 작업을 할 때, 아래 그림처럼 데이터에 순차적으로 접근하여 재고를 처리하길 기대합니다.

실제 작업 순서

그러나 실제로는 같은 데이터를 동시에 변경하려 하기 때문에 재고 감소 작업이 누락될 수 있습니다.

이와 같은 문제를 방지하기 위해 공유 자원에 대해 하나의 스레드만 접근할 수 있게끔 제한하면 되고 그게 동시성 제어입니다.

동시성 제어에는 여러 방법이 있고 상황에 맞게 적절한 방법을 선택하여 구현해주어야 합니다.

Synchronized

스레드 동기화는 멀티스레드 환경에서 여러 스레드가 하나의 공유자원에 동시에 접근하지 못하도록 막는것을 말합니다.

공유데이터가 사용되어 동기화가 필요한 부분을 임계영역(critical section)이라고 부르며, 자바에서는 이 임계영역에 synchronized 키워드를 사용하여 여러 스레드가 동시에 접근하는 것을 금지함으로써 동기화를 할 수 있습니다. 

메서드 선언부에 synchronized 키워드를 붙이거나 코드블럭앞에 사용하고, @Synchronized 어노테이션 추가하여 작동합니다.

단, 데이터에 동시에 하나의 스레드만 접근이 가능하다는 조건이 하나의 프로세스에서만 보장되는 특징인데 ,이러한 특징때문에 Scale-out 시, 즉 서버가 여러 대일 때 동시성이 보장되지 않는다는 치명적인 단점이 있습니다.

이러한 이유때문에 실무에서는 동시성을 해결하는 방법으로 synchronized는 거의 사용하지 않는다고 합니다

비관적 락

테이블에 락을 걸어 다른 트랜잭션에서의 접근을 하지 못하게 하기 때문에 데이터의 일관성이 보장됩니다.

트랜잭션에서 데이터를 사용하기 전 락을 걸기 때문에, 데이터를 변경 중에 다른 트랜잭션과 충돌 가능성이 낮습니다.

Shared lock (읽기 잠금, s-lock) (PESSIMISTIC_READ)
락을 획득한 트랜잭션에서만 대상 레코드를 수정, 삭제 할 수 있으며 락을 획득하지 못한 트랜잭션은 읽기만 허용하는 방법.

고려할 점
데이터 일관성을 보장하지만 동시 접속자가 많은 환경에서는 락 대기 시간으로 인해 성능에 영향을 줄 수 있다.

비관적 락은 특정 레코드를 대상으로 충돌이 자주 발생할 것으로 추측하는 경우 사용하기 적합합니다.

레코드 자체에 락을 걸기 때문에 동시성이 크게 저하될 수 있고 반드시 타임아웃을 지정하여 무한 대기에 따른 데드락이 발생하지 않도록 주의가 필요합니다.

낙관적 락

version(혹은 시간 관련 등의 컬럼으로도 가능) 컬럼을 추가하여 버전이 다르면 업데이트가 불가능하게 하는 방법입니다.

간단히 얘기하자면, 해당 테이블에 변경사항(수정)이 생겼을 때 버전이 올라가는 것입니다.

동시 요청(많은 재시도 횟수가 아님)에 대해 DB에 락을 걸지 않기 때문에, 비관적 락보다 성능 향상에 이점이 있습니다.

낙관적 락은 충돌이 자주 발생하지 않는다고 가정하기 때문에, 많은 사용자가 동시에 데이터에 접근할 수 있습니다. 즉, 처리량을 향상시킬수 있습니다.

반면, 동시에 요청하여 데이터 충돌이 발생했을 때 이를 해결하기 위한 추가적인 로직(재시도 로직)이 필요하여 구현 복잡성이 있습니다.

데이터의 변경 빈도가 높은 시스템에서는 충돌이 자주 발생하기 때문에, 이를 해결하기 위한 추가적인 시간이 필요합니다.

종합

낙관적 락은 일반적으로 비관적 락보다 성능이 좋은게 맞으나, 간혹 데이터 성향에 따라 비관적 락이 더 좋은 경우도 있습니다. 예를들어 재고가 1개인 상품이 있고, 100만 유저가 동시에 주문을 요청하는 상황입니다.

비관적 락의 경우 1명의 유저 외에는 대기를 하다가 미리 트랜잭션 충돌 여부를 파악하게 됩니다. 즉, 재고가 없음을 미리 알리고 복잡한 처리를 하지 않아도 됩니다.

반면 낙관적 락의 경우, 동시 요청을 보낸 유저들에 대해 순차적으로 처리하다가 커밋하는 시점이 되어서야 재고가 없음을 파악하게 됩니다. 또 처리한만큼 롤백도 해야하기 때문에, 자원 소모도 크게 발생하게 됩니다.

최종프로젝트

위와 같이 정리해본 결과를 토대로 비관적 락으로 구현완료
작동확인 완료

profile
새로운 시작~!

0개의 댓글