profile image

L o a d i n g . . .

728x90

이번 포스팅에서는 트랜잭션 동시성을 제어할 수 있는 방법인 two phase locking에 대해 살펴보겠습니다. 2PL(Two phase locking)은 데이터베이스의 serializable isolation level을 구현하는데 자주 사용됐던 방식입니다. 2PC(2 Phase Commit)과 2PL 용어가 비슷해서 헷갈릴 수 있는데요, 2PC은 하나의 트랜잭션으로 처리돼야 할 작업이 여러 DBMS 서버를 거쳐야 하는 경우 트랜잭션의 원자성 보장하기 위해 활용하는 프로토콜입니다. 

2PL(2 Phase Locking) 

2PL는 다수의 트랜잭션이 동시에 실행될 때 conflict serializability를 보장하는 동시성 제어 방법입니다. 2PL의 장점은 conflict serializability를 보장하기 위해서 특정 트랜잭션의 작업을 미리 다 파악할 필요가 없다는 점입니다(기존의 방식은 트랜잭션에서 수행되는 작업을 모두 파악하고 dependency graph를 그려서 cycle여부를 확인하는 등 사전에 필요한 작업을 처리하는데 비용이 큽니다).

Two phase locking은 여러 트랜잭션이 동시에 동일한 데이터에 접근하는 상황에서, 최소 1개 이상의 트랜잭션이 해당 데이터를 수정하려고 할 때 conflict가 발생했다고 간주합니다. 두 스케줄이 동일한 트랜잭션을 실행시키고 conflict관계의 작업 순서가 동일할 때 S1과 S2를 conflict serializable 하다고 말합니다. 예를 들어 다음 두 스케줄은 conflict serializable 합니다. 

<S1>
transaction-1 reads X 
                                                   transaction-2 reads Y 
transaction-1 writes X 
                                                   transaction-2 writes Y 
<S2 - 순차 실행 스케줄>
transaction-1 reads X 
transaction-1 writes X 
                                                   transaction-2 reads Y 
                                                   transaction-2 writes Y 

우선 S1과 S2에서 실행되는 트랜잭션의 작업이 동일한 것을 볼 수 있습니다. 그리고 트랜잭션의 작업 중 서로 conflict 관계에 있는 작업은 (transaction-1 reads X, transaction-1 writes X)와 (transaction-2 reads Y, transaction-2 writes Y)입니다. Conflict 관계에 있는 작업의 순서가 S1과 S2에서 동일하기 때문에 두 스케줄은 conflict serializable 하다고 할 수 있습니다. 

 

2PL의 동작 원리 

2PL은 growing과 shrinking 단계로 진행됩니다. 각 단계에 대해 살펴보겠습니다. 

Growing 

각각의 트랜잭션은 트랜잭션 매니저에게 특정 데이터에 접근하기 위한 잠금을 요청합니다. 트랜잭션 매니저는 상황에 맞게 잠금 요청을 승인하거나 거부할 수 있습니다. 

Shrinking 

각각의 트랜잭션은 소유한 잠금을 해제할 수 있는 단계입니다. 이 단계에서 트랜잭션에서 새로운 잠금을 획득할 수 없습니다. 

출처:https://15445.courses.cs.cmu.edu/fall2022/slides/16-twophaselocking.pdf

위의 그림처럼 shrinking phase에서 새로운 잠금을 획득하려 시도하는 것은 2PL 원리에 부합하지 않습니다. 

2PL의 특성 

2PL을 활용하면 conflict serializability를 보장할 수 있습니다. 하지만 2PL를 사용했을 때 단점은 동시에 실행하던 트랜잭션을 모두 abort 하는 cascading abort가 발생한다는 점입니다. 또한 dirty read현상이 발생할 수 있습니다. Strong Strict 2PL은 dirty read를 방지할 수 있도록 2PL을 보강한 프로토콜입니다. 

Strong Strict 2PL 

기존의 2PL은 shrinking 단계의 어느 시점에서든 잠금을 해제할 수 있습니다. Strong Strict 2PL의 경우 shrinking 단계의 마지막 순간에만 잠금을 해제할 수 있습니다. Strong Strict 2PL에서 growing 단계에서 잠금이 걸린 데이터는 다른 트랜잭션에 의해 읽히거나 덮어 씌워지지 않습니다. 따라서 동시 실행되는 트랜잭션 중 하나가 실패하더라도 cascading abort 없이 동작할 수 있습니다. 

출처:https://15445.courses.cs.cmu.edu/fall2022/slides/16-twophaselocking.pdf

2PL Deadlock 

Deadlock이란 다수의 트랜잭션이 서로의 동작이 끝나기를 기다리면서 무한 대기하는 현상입니다. 2PL은 deadlock을 피하기 위해서 deadlock detection 또는 deadlock prevention 방법을 활용합니다. 

Deadlock Detection 

트랜잭션 간 의존관계를 그래프의 형태로 추적하면서 그래프에 cycle이 발생하면 cycle을 제거할 수 있도록 트랜잭션을 rollback 시키는 방식입니다.

다음 사항을 고려해 rollback 할 트랜잭션을 선택합니다. 
- timestamp 
- progress(트랜잭션의 진척도) 
- 획득한 잠금의 수 
- 함께 rollback 해야 하는 트랜잭션의 수 

Deadlock Prevention 

트랜잭션이 다른 트랜잭션에서 잠금을 획득한 데이터에 접근하려고 할 때 DBMS는 deadlock prevention을 위해 두 트랜잭션 중 하나를 종료시킵니다. 이 방법을 활용하면 별도의 deadlock 추적을 위한 그래프가 필요하지 않습니다. Deadlock prevention은 두 트랜잭션의 timestamp를 비교해서 어떤 트랜잭션을 종료시킬지 결정합니다. 더 오래된 timestamp일수록 더 높은 우선순위를 가집니다. 

  • Wait-Die("Old Waits for Young") : 잠금 획득을 요청하는 트랜잭션(T1)의 timestamp가 잠금을 획득한 트랜잭션(T2)의 timestamp보다 오래됐다면(우선순위가 높다면), T1은 대기할 수 있습니다. 만약 T1의 timestamp가 더 최근이라면 T1은 abort 됩니다.
  • Wound-Wait("Young Waits for Old"): 잠금 획득을 요청하는 트랜잭션(T1)의 timestamp가 잠금을 획득한 트랜잭션(T2)의 timestamp보다 오래됐다면(우선순위가 높다면), T2는 abort 되고 잠금을 해제합니다. 만약 T1의 timestamp가 더 최근이라면 T1은 잠금 획득을 위해 대기합니다. 

 

마무리 

이번 포스팅을 통해 2PL에 대해 살펴봤습니다. 다음 포스팅에서는 timestamp를 통해 동시성을 제어하는 timestamp ordering concurrency protocol에 대해 살펴보겠습니다. 

728x90
복사했습니다!