동시성 제어는 다중 접속 데이터베이스 환경에서 동시에 여러 트랜잭션이 실행 될 때, 이상 현상이 발생하지 않도록 트랜잭션의 실행 순서를 제어하는 것이다. 트랜잭션들이 실행 될 때, 같은 데이터에 대해서 동시에 read/wirte operation이 있다면 예상치 못한 동작이 발생할 수 있다.
이것을 해결하는 방법이 바로 Lock(잠금 기법)이다.
Keyword
write lock, read lock, 2PL, S2PL, SS2PL
데이터마다 lock이 있어서, 데이터를 변경하거나 읽으려면 lock을 취득해야 한다.
만약 lock을 취득하지 못하면 lock을 취득할 때 까지 기다려야 한다.
하지만 Lock만을 사용해서는 Serializablilty를 보장할 수 없다.
예시를 하나 살펴보자.
- tx1 : x와 y의 합을 x에 저장하는 작업 수행
- tx2 : x와 y의 합을 y에 저장하는 작업 수행
위의 작업을 serial하게 실행하게되면 결과는- serial schedule #1 (tx1 - tx2)
x = 300, y = 500- serial schedule #2 (tx2 - tx1)
x = 400, y = 300
serial schedule #1, #2와 결과값이 다르므로 아래의 schedule은 Nonserializable하다.
이상현상이 발생한 이유는
tx2가 먼저 실행 되었으므로, tx1에서 y값을 읽어올 때는 업데이트 된 y=300을 읽어와야 한다.
그러나 tx1의 read(y)는 y의 초기값 200을 읽어왔기 때문에 문제가 발생.
결과값이 달라지는 이상현상을 unlock과 write/read lock operation 순서를 바꿈으로써 해결한다.
- tx2가 먼저 실행되었기 때문에, 빨간색 박스의 unlock과 write-lock 순서를 바꿔 해결할 수 있었다.
- tx1이 먼저 실행되었다면, 노란색 박스의 unlock과 write-lock의 순서를 바꿔주어야 한다.
트랜잭션에서 모든 locking operation이 최초의 unlock operation 보다 먼저 수행되도록 하는 것을 말한다.
위에서 처럼 이상현상을 해결하기 위해 unlock과 lock의 위치를 바꾸면 아래와 같이 2개의 phase가 형성된다.
2PL 프로토콜은 Serializability(직렬화)를 보장한다.
하지만 2PL 프로토콜은 dead-lock(교착상태)가 발생할 수 있다.
교착상태에 빠지면 외부에서 강제로 트랜잭션을 중단하거나,잠금을 해제하지 않는 이상
무한정 대기 상태로 남게 된다.
해결방법으로는 Timeout-based 기법, DeadLock Prevention 기법이 있다.
이부분은 추가적인 공부가 필요함.
초창기에는 동시성 제어를 구현하기 위해 lock기법을 사용했다.
serializability를 보장하기 위해서 2PL 프로토콜을 사용하였고,
recoverability를 보장하기 위해서 S2PL, SS2PL을 사용하였다.
지금은 성능을 올리기 위해서 MVCC (Multiversion concurrency control)이 사용되고 있다.
Reference
쉬운코드 - LOCK을 활용한 concurrency control 기법
동시성 제어 기법 — 잠금(Locking) 기법