2 minute read

DB Lock의 종류

Pessimistic Lock (비관적락)

실제로 데이터에 Lock을 걸어서 정합성을 맞추는 방법입니다. exclusive lock을 걸게되면 다른 트랜잭션에서는 lock이 해제되기전에 데이터를 가져갈 수 없게 됩니다. 비관적락은 데드락이 발생할 수 있기 때문에 주의해서 사용해야 됩니다.

image

image

Jpa의 어노테이션을 이용해서 쓰기락을 설정해 select for update로 쿼리가 실행되는 것을 확인할 수 있습니다.


image

스레드 1이 조회를 했을 때 쓰기 락을 걸어서 다른 스레드에서 공유 자원인 Stock에 접근하지 못하게 막습니다. 스레드 2는 스레드1의 쓰기 락이 끝날 때까지 대기하다가 Stock 에 접근하게 됩니다.


  • 장점
    • 충돌이 빈번하게 발생한다면 낙관적 락보다 성능이 좋을 수 있습니다.
    • 락을 통해 수정을 제어하기 때문에 데이터 정합성이 보장될 수 있습니다.
  • 단점
    • 락을 통해 정합성을 보장하기 때문에 성능이 감소될 수 있습니다.



Optimistic Lock (낙관적락)

실제로 Lock을 이용하지 않고 버전을 이용함으로서 정합성을 맞추는 방법입니다. 먼저 데이터를 읽은 후에 update를 수행할 때 현재 내가 읽은 버전이 맞는지 확인하여 업데이트를 합니다. 내가 읽은 버전에서 수정사항이 생겨 버전이 변경되었을 때에는 어플리케이션에서 다시 읽은 후에 작업을 수행해야합니다.

image

image

update를 할 때 버전을 비교하는 것을 확인할 수 있습니다.

현재의 예시 상황에서는 Pessimistic Lock을 이용한 경우에 테스트가 1~2초 정도 걸렸는데 Optimistic Lock은 재시도 로직때문에 테스트가 6초 정도 걸리게 되었습니다.


image

스레드 1과 스레드 2가 버전이 1인 데이터를 가져갑니다. 스레드 1이 업데이트를 할 때 버전을 업데이트 해주고 Stock의 버전은 2가 되게 됩니다. 스레드 2가 업데이트를 할 때 처음 조회한 버전인 1로 현재 Stock의 버전과 일치한지 비교합니다. 현재 데이터의 버전과 다르므로 실패하게 됩니다.


  • 장점
    • 충돌이 빈번하게 일어나지 않는다면 별도의 락을 설정하지 않으므로 Pessimistic Lock보다 성능상 이점이 있을 수 있다.
  • 단점
    • update가 실패했을 때 재시도 로직을 개발자가 직접 작성해주어야 한다.
    • 충돌이 빈번하게 일어난다면 Pessimistic Lock이 이용하는 것이 성능상 더 좋다.



Named Lock

이름을 가진 metadata Locking입니다. 이름을 가진 Lock을 획득한 후 해제할 때까지 다른 세션은 이 Lock을 획득할 수 없습니다. 주의할 점으로는 트랜잭션이 종료될 때 Lock이 자동으로 해제되지 않기 때문에 별도의 명령어로 해제를 수행해주거나 선점 시간이 끝나야 해제됩니다.

Pessimistic Lock은 row나 테이블 단위로 락을 거는 것이고 Named Lock은 메타 데이터에 락을 거는 것입니다.

세션 1이 ‘1’이라는 이름으로 Lock을 건다면 다른 세션에서는 세션 1이 락을 해제한 후에 락을 획득할 수 있습니다.

image

편의를 위해서 Jpa를 native query 기능을 이용했지만 실제로는 Datasource를 분리하는 것이 좋다고 합니다. 같은 DataSource를 사용한다면 커넥션 풀이 부족한 현상이 발생할 수 있다고 합니다. 락을 해제하지 않는다면 데이터소스가 부족해질 수도 있고 락 획득에 필요한 커넥션 1개, 수량 감소 로직에 필요한 커넥션 1개 총 2개를 사용하기 때문이기도 합니다.


퍼사드 객체를 이용해 락을 획득하고 해제하는 메서드를 꼭 작성하고 그 사이에 수량을 감소시키는 서비스 메서드를 작성해주었습니다.

image


서비스 메서드에서는 부모의 트랜잭션과 별도로 실행되기 위해 전파 레벨을 Requires_new로 변경해주었습니다.

별도의 트랜잭션으로 분리를 해주어 데이터베이스에 정상적으로 commit 이 된 이후에 락을 해제하기 위함입니다.

image


NamedLock은 주로 분산락을 구현할 때 사용합니다. Pessimistic Lock은 타임아웃을 구현하기에 힘들지만 NamedLock은 구현하기 쉽습니다. 데이터 삽입시에 데이터 정합성을 맞추기 위해서도 사용합니다.

트랜잭션 종료시 락해제와 세션 관리를 잘해야하므로 주의해서 사용해야 합니다. 예시는 간단하게 구현한 것이지만 실제로는 구현하기 복잡할 수도 있다고 합니다.



참고

재고시스템으로 알아보는 동시성 이슈 해결방법

Categories: ,

Updated: