참고 자료
유투브 쉬운코드 LOCK을 활용한 concurrency control
Lock
데이터베이스 락(lock)은 동시성 문제를 방지하고 데이터의 무결성을 유지하기 위해 필수적이다.
락을 걸지 않으면 여러 트랜잭션이 동시에 동일한 데이터를 수정하려고 할 때 충돌이 발생하여 데이터가 손상되거나 일관성을 잃을 수 있다.
즉, 이상 현상이 일어날 수 있다.
예제1
흐름
x 시작: 50
트랜잭션1: write_lock 획득
트랜잭션2: write_lock 획득 X
트랜잭션1: x = 20 변경
트랜잭션1: write_lock 반환
트랜잭션2: write_lock 획득
트랜잭션2: x = 90 변경
트랜잭션2: write_lock 반환
예제2
흐름
x 시작: 10
트랜잭션1: write_lock 획득
트랜잭션2: read_lock 획득 X
트랜잭션1: x = 20 변경
트랜잭션1: write_lock 반환
트랜잭션2: read_lock 획득
트랜잭션2: x read(20)
트랜잭션2: read_lock 반환
write_lock (exclusive lock)
read/write(insert, update, delete) 할 때 사용한다
다른 트랜잭션이 같은 데이터를 read/write 하는 것을 허용하지 않는다.
read_lock (shared lock)
read 할 때 사용된다
다른 트랜잭션이 같은 데이터를 read 하는 것은 허용한다
예제3
흐름
x 시작: 10
트랜잭션2: read_lock 획득
트랜잭션1: write_lock 획득 X
트랜잭션2: x read(10)
트랜잭션2: read_lock 반환
트랜잭션1: write_lock 획득
트랜잭션1: x = 20 변경
트랜잭션1: write_lock 반환
예제4
흐름
x 시작: 10
트랜잭션2: read_lock 획득
트랜잭션1: read_lock 획득
트랜잭션1: x read(10)
트랜잭션2: x read(10)
트랜잭션1: read_lock 반환
트랜잭션2: read_lock 반환
Lock 호환성
read-lock | write-lock | |
read-lock | O | X |
write-lock | X | X |
Lock을 써도 생기는 이상한 현상 예제1
트랜잭션1: x에 대한 write_lock, y에 대한 read_lock 필요
트랜잭션2: x에 대한 read_lock, y에 대한 write_lock 필요
serial schedule #1
트랜잭션1에서 x = 300 y = 200
트랜잭션2에서 x = 300 y = 500
최종적으로 x = 300 y = 500
serial schedule #2
트랜잭션2에서 x = 100 y = 300
트랜잭션1에서 x = 400 y = 300
최종적으로 x = 400 y = 300
Nonserializable example
현재 schedule에서는 serial schedule에서 나올 수 있는 가능성인 (x=300, y=500) / (x=400, y=300) 과 다르게 x=300, y=300으로 이상한 결과가 나왔다.
즉, 락을 사용했어도 이상 현상이 발생했다.
하지만 해당 그림에서 트랜잭션2의 unlock(x) x 락 반환 보다 write_lock(y) 락 획득이 먼저 실행되면 이런 현상이 일어나지 않는다.
트랜잭션2가 write_lock(y)를 획득하는 순간 트랜잭션1은 read_lock(y)를 획득하지 못해서 블락 상태가 된다.
그래서 트랜잭션2가 y에 대한 락 해지를 해야만 진행이 가능하다.
2PL protocol (two-phase locking)
현재 그림은 원래의 각 트랜잭션 operations 순서이다.
실행 순서에 따라 이상 현상이 발생할 수 있음을 우린 예제로 확인했다.
현재 그림은 트랜잭션1에서는 write_lock(x), unlock(y) 순서를 바꾸고 트랜잭션2에서는 write_lock(y)와 unlock(x) 순서를 바꿨다.
이렇게 진행하면 이상 현상이 발생하지 않는다.
현재 그림은 락 획득 / 반환 operations 만 표시한 schedule 이다.
특징은 모든 락 획득 operations이 최초의 unlock operation 보다 먼저 수행한다는 것이다.
이런 방식의 락 프로토콜을 2PL protocol(two-phase locking)이라고 한다.
2PL protocol은 2단계를 통해 진행한다.
Expanding Phase(Growing Phase)
lock을 취득하기만 하고 반환하지는 않는 phase
Shrinking Phase(Contracting Phase)
lock을 반환만 하고 취득하지는 않는 phase
2PL protocol은 Serializability를 보장한다.
2PL protocol & Dead Lock
현재 2PL - protocol 사용
트랜잭션2: x에 대한 read_lock 획득
트랜잭션1: y에 대한 read_lock 획득
트랜잭션1: x에 대한 write_lock 획득 불가능
트랜잭션2: y에 대한 write_lock 획득 불가능
→ dead lock (교착 상태)
즉, 2PL 에서는 dead lock 상태가 발생할 수 있다.
2PL protocol 종류
해당 예제는 2PL protocol 종류를 이해하기 위한 예제이다.
x에 대해서는 읽기 작업만 필요하니 read_lock y,z에 대해서는 읽기/쓰기 작업이 필요하니 write_lock을 획득한다
Conservative 2PL
모든 필요한 lock을 취득한 뒤 트랜잭션을 시작
deadlock-free
실용적이지 않다 (트랜잭션을 시작하기가 어렵다)
Strict 2PL (S2PL)
strict schedule을 보장하는 2PL
recoverability 보장
write_lock을 commit / rollback 될 때 반환
recoverability & strict schedule 설명 링크
https://20240228.tistory.com/408
Strong Strict 2PL (SS2PL)
strict schedule을 보장하는 2PL
recoverability 보장
read-lock / write-lock 모두 commit / rollback 될 때 반환
S2PL 보다 구현이 쉽다
2PL protocol 단점
read-read를 제외하고는 한 쪽이 block 되니까 전체 처리량이 좋지 않다
그래서 MVCC(Multiversion Concurrency Control)가 등장했다.
초창기 DBMS는 2PL 중에 recoverability를 보장하는 S2PL과 SS2PL을 많이 사용했지만 2PL의 처리량 문제를 비롯한 여러 단점으로 인해 현재는 MVCC를 많이 사용한다.
'DataBase > MySQL' 카테고리의 다른 글
[MySQL] DB 인덱스(index) (3) | 2024.11.15 |
---|---|
[MySQL] MVCC(Multi Version Concurrency Control) (3) | 2024.11.14 |
[MySQL] 트랜잭션 격리 레벨 (6) | 2024.11.14 |
[MySQL] concurrency control 기초2 (recoverability) (1) | 2024.11.13 |
[MySQL] concurrency control 기초1 (schedule, serializability) (1) | 2024.11.13 |