CS/데이터베이스

동시성 제어(Concurrency Control)

Junuuu 2021. 12. 12. 23:37

Lock-based protocol

트랜잭션 A, B가 가 동시에 수행될 때 다른 트랜잭션이 권한을 요청할 때 사용되고 있다면 lock을 걸어 사용할 수 없도록 하는 방식

 

데이터베이스 전체를 lock 하면 쉽지만 본질적으로 Concurrent 하지 않음

 

Lock의 범위를 테이블로 축소하면 동시성은 늘어나지만 문제는 생길 여지는 있음.

 

동시성을 최대한 늘리면서 비일관성이 일어나지 않게 하는 것이 우리의 목표

 

 

Lock을 걸면 항상 동시성이 제어될까?

lock을 짧게 걸게 되면 비일관성이 발생함

 

A+B = 항상 300으로 유지되어야 하는데 display(A + B) = 250이 돼버렸음..

 

어떻게 해결하면 될까?

lock을 밑에 걸어버리면 비일관성을 해결할 수 있음.

밑에 걸면 모든 게 끝인가?

 

하지만 교착상태(DeadLock)에 걸릴 수 있음

DeadLock이란?

둘 이상의 프로세스들이 자원을 점유한 상태에서 다른 프로세스가 점유하고 있는 자원을 무한정 기다리는 현상

 

아래의 상황에서는 T3와 T4가 자원(A, B)을 점유한 상황에서 서로의 자원을 무한정 기다림

Deadlock

어떻게 해결해야 할까?

둘 중의 하나의 lock을 풀게 되면 DeadLock이DeadLock 풀릴 수 있음

 

 

Shared lock

Read Lock이라고도 불리며 데이터를 읽을 때 사용되어지는 Lock입니다.

Shared Lock 끼리는 동시에 접근이 가능합니다

즉, 하나의 데이터를 읽는 것은 여러 사용자가 동시에 할 수 있다는 것입니다.

 

Shared lock인 T1에 Shared lock인 T2는 접근 할 수 있다.

Shared lock인 T1에 Exclusive lock인 T2는 접근 할 수 없다.

 

Exclusive lock

Write Lock이라고도 불리며 데이터를 변경할 때 사용되는 Lock입니다. 

Exclusive Lock에는 접근할 수 없습니다.

Exclusive lock인 T1에 Shared lock인 T2는 접근을 할 수 없다.

Exclusive lock인 T1에 Exclusive lock인 T2는 접근 할 수 없다.

 

 

ReetrantLock vs ReeantrantReadWriteLock

Conflict Serializability에서 read 끼리는 바뀌어도 Conflict Serializable 하지만 read write가 바뀌면 Conflict Serializable 하지 않음을 이용한 2개의 라이브러리

 

ReetrantLock에는 Read, Write에 exclusive lock이 걸리는 방법

 

즉, ReeantrantReadWriteLock을 쓸 경우에 좀 더 효율적인 자원을 사용할 수 있다. ( Read에 shared lock이 걸리고, Write에는 exclusive lock이 걸리는 방법)

Starvation

Exclusive lock과 shared Lock의 차이점 때문에 T2는 영원히 접근을 못할 수도 있음

Starvation

 

이를 기아 상태(Starvation)라고 부른다.

Lock이 충돌하면 Fail 되는 방법으로 stavation을 해소할  수 있습니다.

 

 

Lock을 걸어서 동시성을 제어하려면 어떻게 해야 할까요? 

two-phase locking protocol이란 방법을 사용하면 transaction이 serialization 하다고 합니다.

 

Two-phase locking protocol(2PL)이 왜 confict serializability를 보장할 수 있을까?

2PL confict serializability 하지 않다면 어떤 트랜잭션 X non-serializable schedule을 가질 것이다.

X non-serializable schedule T1, T2, T3, …… , Tn을 만들었을 때 precedence graph의 사이클 유무로 판단했을 때 사이클이 있을 것이다.

그 사이클을 T1 -> T2 -> T3 -> … -> Tn -> T1이라고 하자.

A(i)를의LOCK POINT라고 하자.

그렇다면 모든 트랜잭션 T(i) -> T(j)에 대하여 A(i) < A(j)가 성립하며 우리의 사이클 t1 -> t2 -> t3 -> …. -> tn  -> t1  a1 < a1 < ……. < an < a1을 만족해야 하지만 이는 모순이다.

 

Two-phase locking protocol

2개의 phase로 구분이 됩니다.(Two-phase)

Growing phase(락을 계속 거는 phase), Shrinking phase(락을 계속 푸는 phase)

가장 고점을 Locked point라고 한다.

아래의 그림을 통해 이해할 수 있습니다.

Two-phase locking protocol

 

2PL example

파란색은 Growing phase, 빨간색은 Shrinking phase을 나타냅니다

2PL example

파란색은 Growing phase, 빨간색은 Shrinking phase을 나타냅니다

 

그러면 T1과 T2는 2PL(two-phase locking protocol)을 따를까요?

 

T1, T2 two-pahse locking protocol을 따르지 않음.

 

왜? 중간에 lock unlock이 발생하기 때문에

 

 

그렇다면 항상 lock을 맨뒤에 사용해야 할까요?

lock을 항상 맨뒤에 할 필요 없이 당겨 올 수 있을 만큼 당겨오면 db의 자원을 효율적으로 사용할 수 있습니다.

 

 

 

2PL의 문제점

DEADLOCK이 발생할 수 있다.

Deadlock을 막을 순 없을까?

Deadlock을 막기 위해서는 시스템의 처리량이나 효율성이 떨어지는 단점이 발생하기 때문에 완벽하게 막지는 않습니다.

 

 

T5 가 rollback 되면 T6, T7 도 rollback 되어야 하기 때문에 Cascading rollback이 발생함.

 

어떻게 Cascading rollback을 막을 수 있을까?

 

Strict two-phase locking protocol을 사용하면 Cascading rollback을 막을 수 있다.

lock을 미리 풀게 되면 동시성을 증가시킬 순 있으나 cascading rollback을 유발할 수 있다.

- lock-X에 대해 commit 전까지 unlock 하지 않음

 

Rigorous two-phase locking protocol

위와 유사하지만 lock-X과 lock-S에 대해 commit 전까지 unlock하지 않음

 

 

 

DB가 자동으로 lock, unlock을 하는 방식

T8의 경우에는 초반에 read만 하지만 lock-X가 걸려있어서 T9에서 계속 기다려야 함

따라서 upgrade를 활용하여 read 할 때 lock-S로 초기에 걸고  write를 하기 전에 upgrade를 통해 lock-X로 만듦

 

 

read를 하려면 Shared-Lock을 건다

write를 하려고 하는데 Shared-Lock이 걸려 있으면 upgrade 그렇지 않으면 Exclusive-Lock을 건다.