DB Lock

newVelog·2024년 7월 11일
0

CS

목록 보기
30/31

Lock 이란?

아래 그림과 같이 데이터가 존재하고 여러 커넥션들이 수정 요청이 동시에 발생하게 되면 커넥션이 오는 순서에 따라서 데이터 값이 어떻게 변경될지 모른다는 문제가 생기게 된다.

이때 데이터의 일관성에 문제가 생기게 되고 이 문제를 해결하는 방법 중 하나가 Lock 이다.


Lock을 설정하게 된다면 데이터에 제일 먼저 접근한 커넥션이 자물쇠를 잠그게 된다.
나머지 커넥션들은 자물쇠가 잠겨져 있어서 데이터에 접근할 수가 없게 되고 앞선 커넥션의 연산이 끝날때까지 대기하고 그 다음 커넥션이 데이터에 접근 할 수 있게 된다.
이렇게 자물쇠를 걸고 푸는 행위를 Lock이라고 한다.

Lock 전략

낙관적 Lock

트랜잭션이 애초에 충돌이 발생하지 않는다 라고 가정하고 사용하는 Lock 전략

  • 트랜잭션이 충돌이 되면 조취를 취하게 된다.
  • 낙관적 Lock은 애플리케이션 Lock이라고도 하는데, 애플리케이션 내에서 버전이라는 것을 통해서 Lock을 구현할 수 있기 때문이다.

비관적 Lock

트랜잭션이 애초에 매번 충돌이 발생한다 라고 가정하고 사용하는 Lock 전략

  • 데이터를 접근할 때 트랜잭션이 충돌할 것이라 생각하고 바로 Lock을 걸게 된다.
  • 비관적 Lock은 데이터베이스 트랜잭션 Lock이라고 하는데, 대표적으로 select for update 가 있다.

JPA에서의 낙관적 & 비관적 Lock

동시성 문제 발생

아래는 20명의 사용자가 동시에 5개의 쿠폰을 발급하는 상황의 테스트 코드이다.

분명 5개의 쿠폰만 발급 할 수 있는데 20개의 쿠폰이 발급되었고 이 문제를 Lock으로 해결할 수 있다.

낙관적 Lock으로 해결

JPA에서의 낙관적 Lock을 사용하기 위해서 @Version을 사용하면된다.
단순하게 1,2,3,4 와 같은 버전이고 이 엔티티에 접근해서 값이 변경될 때 버전이 같이 올라가게되어 현재 버전이 맞는지 아닌지 검사하기 위한 숫자일 뿐이다.
현재 버전이 맞는지 확인을 하고 나서 값을 변경하게 되고 값을 변경할 때 같이 버전도 변경하는것을 확인 할 수 있다.

테스트 결과로는 3개의 쿠폰이 동시에 발급되는 것을 알 수 있다.
20명의 사용자가 5장의 쿠폰을 동시에 발급했는데 3장의 쿠폰만 발급된 이유는 JPA에서의 낙관적 Lock은 최초의 요청만 커밋하기 때문이다.

아래와 같이 카운트가 존재하는데 트랜잭션 A가 이 카운트 값을 수정하기 위해서 트랜잭션을 시작한다. 이때 버전이 1이다.
동시에 트랜잭션 B, C, D도 접근을 하게 된고 아직 수정 연산을 시작하지 않았기 때문에 버전이 1이다.

A가 연산을 시작하고 현재 버전이 1이기 때문에 버전이 일치해 카운트 값을 변경 시키게 된다.
버전의 값도 동시에 2로 변경을 시키고 이때 트랜잭션 B, C, D도 수정 연산을 하려고 하는데 버전이 맞지 않게 되어 낙관적 Lock을 얻을 수 없어서 애초에 카운트에 대한 수정 연산을 할 수 없게 된다.

JPA에서의 낙관적 Lock은 최초 요청만 커밋하기 때문에 쿠폰의 개수가 1 ~ 5개가 될 수 있다.
하지만 동시성 문제가 발생한 상황에서의 테스트와 달리 5개의 쿠폰 개수가 넘지 않는다는 것은 보장이 된다.

비관적 Lock으로 해결

JPA에서의 비관적 Lock은 @Lock과 함께 Lock 모드 타입을 PESSIMISTIC_WRITE를 사용하면 된다.

테스트를 돌려보면 정확하게 5개 쿠폰만 발급되는 것을 알 수 있다.
비관적 Lock은 데이터에 접근할 때부터 바로 자물쇠에 잠그기 때문에 20명의 사용자가 쿠폰을 발급할 경우에는 트랜잭션 하나가 들어가는 순간 나머지 트랜잭션은 모두 대기하고 앞선 트랜잭션이 종료되면 다음 트랜잭션 순차적으로 실행되게 된다.
그렇기 때문에 20개의 트랜잭션 중 정확히 5개 트랜잭션만 정상 실행되고 나머지는 쿠폰의 개수 부족해 바로 Exception을 발생시켜 정확하게 5개 쿠폰만 발생할 수 있다.

select for update는 트랜잭션이 데이터에 접근할 때부터 Lock을 거는 쿼리이다.

카운트에 트랜잭션 A가 select for update를 통해서 접근을 하면 Lock이 걸리고 나머지 트랜잭션들은 접근하지 못하고 계속 기다리고 있게 된다.
트랜잭션 A의 연산이 완료되면 Lock이 풀리고 그때 다른 트랜잭션들이 접근할 수 있게 된다.

출처 : https://www.youtube.com/watch?v=LDi5muN2kgI

0개의 댓글