이전에 낙관적 락에 작성하였습니다.
낙관적 락을 요약하자면 아래와 같습니다.
•
데이터를 읽을때 버전 상태를 확인
•
데이터를 수정할 때 현재 데이터의 버전을 확인합니다. 이때 다른 사용자가 수정하지 않았으면 업데이트가 진행이되고, 버전이 변경되었으면 충돌 난 것으로 확인하고 수정 작업은 실패하고 충돌된 데이터를 해결하기 위해 추가 작업을 애플리케이션에서 진행합니다.
단점
•
데이터 수정이 많은 로직에는 충돌이 많이 발생하여, 유저의 피로감이 높아져 서비스 유입에 좋지 않은 결과를 초래할 것입니다.
이를 해결하는 방법중 하나로 비관적 락을 사용합니다.
비관적 락(Pessimistic)
•
모든 트랜잭션이 충돌이 날 것이고, 우선적으로 Lock을 점유하여 접근하지 못하게 하는 방법입니다.
•
데이터를 수정할 때 x-Lock을 점유하고 있으므로, 충돌이 발생할 가능성이 적습니다.
•
사용자가 수정할 때 까지 다른 사용자는 스핀락으로 대기를 하고있습니다.
때문에 비관적락 같은경우 Time-out 설정을 통하여, 언제가지 대기를 할 것인지 꼭 지정해 줘야합니다.
•
비관적 락 경우 next-Lock(갭락)을 사용하기 때문에 갭락이 무엇이고, 어떻게 동작하는 지 알아두면 비관적락을 사용할때 큰 도움이 될 것입니다.
◦
갭락 혹은 next-lock은 레코드 자체에 락을 거는 것 뿐만아니라, 해당 레코드의 앞뒤에 “갭”에도 락을 거는 방식입니다. 이는 트랜잭션이 실행하는 동안 새로운 레코드가 해당하는 범위에 데이터를 삽입되는 것을 방지합니다. [갭락 설명 블로그 : https://idea-sketch.tistory.com/46]
S-Lock이란?
Shared Lock 이라고 하고, 다수의 트랜잭션이 동시에 특정 리소스(예: 데이터베이스의 행이나 테이블)를 읽을 수 있도록 허용하는 잠금 메커니즘입니다. 가장 큰 특징으로는 S-Lock이 걸려 있는 동안에는 X-Lock을 획득 할 수 없으며, 수정이 불가능합니다.
X-Lock이란?
Exclusive Lock 이라 하고, 데이터 베이스에 특정 리소스를 단일 트랜잭션만 접근가능하도록 합니다. X-Lock이 걸린 상태에서는 S-Lock, X-Lock이 접근하지 못합니다.
동시성 테스트
아래 코드는 동시성 테스트를 위한 코드입니다.
동시성 테스트 코드
비관적 락을 사용한 동시성 문제 해결
•
비관적 락 사용자 1
1.
사용자1 : X-Lock을 획득하여 다른 사용자가 접근하지 못하게 합니다.
2.
사용자2: 스핀락을 통하여 락을 획득할 때 까지 대기합니다.
3.
사용자3: 같은 사유로 락을 획득할때 까지 대기합니다.
4.
사용자4 : 같은 사유로 락을 획득할 때 까지 대기합니다.
•
사용자 2 락획득
1.
사용자 1: 데이터를 update or insert후 x-lock을 반환합니다.
2.
사용자2: x-lock을 획득하여 update or insert를 진행합니다.
3.
사용자3: 스핀락을 통하여 락을 획득할 때 까지 대기합니다.
4.
사용자4: 같은 사유로 락을 획득 할 때까지 대기합니다.
그렇다면 비관적 락은 왜 사용하는 것일까?
•
데이터 무결성 보장: 데이터 무결성을 강력하게 보장할 수 있어, 특히 트랜잭션 처리에서 안정성을 높일 수 있습니다.
•
충돌 방지: 데이터에 락을 설정함으로써, 동시에 발생할 수 있는 데이터 수정 충돌을 효과적으로 방지할 수 있습니다.
비관적 락은 언제 사용하면 좋은가?
•
여러 사용자가 동시에 같은 데이터를 수정할 가능성이 높은 경우, 예를 들어 은행 시스템의 계좌 이체와 같은 트랜잭션 처리에서 자주 사용됩니다.
•
데이터의 정확성과 일관성이 매우 중요한 경우
[실습]
•
JPA에서 비관적 락을 사용하는 방법
public interface ProductRepository extends JpaRepository<ProductEntity, Long> {
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("SELECT p FROM ProductEntity p WHERE p.id = :id")
@QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value = "10000")})
Optional<ProductEntity> findByIdWithPessimisticLock(Long id);
}
JavaScript
복사
•
select for update를 사용하여 X-lock을 획득 하는 것을 볼 수 있습니다.
•
동시성 또한 문제 없이 통과 한 것을 볼 수있습니다.
◦
final stock : 10
오늘은 비관적 락에 설명하게 되었습니다.
비관적 락을 사용하면서 중요한 점은 timeout 설정을 안하면 락을 획득할 수 때까지 계속 대기해야 되는 상황이 발 생 될 수 있으므로 지정하는게 좋으며, 갭락 next-lock을 생각하여 발생할 수 있는 문제에대해 생각하고 구현해야 됩니다.
다음에는 분산락 에대해 작성하도록 하겠습니다.
비관적 락에서 next-lock에 의해 발생되는 DeadLock 예제