5 분 소요

Database System

Concurrency Control

Locking Approach

image

Lock-Based Protocols

잠금(locking)은 데이터 항목에 대한 동시 액세스를 제어하는 ​​메커니즘입니다. 트랜잭션에 대한 데이터 항목을 읽거나 쓸 수 있는 권한을 얻습니다. 잠금은 각 데이터 항목과 연결된 변수입니다. 읽기 또는 쓰기가 가능한 상태를 보여줍니다. 데이터 항목은 두 가지 모드로 잠글 수 있습니다.

  • S-Lock(A) : 공유(Shared)
    • 트랜잭션 T가 데이터 항목 A에 대해 S-Lock을 획득하면 T는 A를 읽을 수 있습니다.
  • X-Lock(A) : 배타/독점(Exclusive)
    • 트랜잭션 T가 데이터 항목 A에 대해 X-Lock을 획득하면 T는 A를 쓸 수 있습니다.
  • 잠금 해제(A)
    • 트랜잭션 T가 데이터 항목 A에 대한 읽기/쓰기를 완료하면 T는 A에 대한 모든 잠금을 해제합니다.

Compatible Locking Table

image

  • 여러 개의 트랜잭션이 해당 값을 읽기 위해 데이터 항목에 S-lock을 적용합니다. 하나의 트랜잭션만 쓰기를 위해 데이터 항목에 X-lock을 적용합니다.
  • 예를 들어, Ti가 데이터 항목 A에 대해 X-LOCK을 보유하고 있다고 가정합니다. Tj가 A에 대해 S-LOCK을 요청하면 이 요청은 거부됩니다. Tj는 Ti가 X-LOCK을 해제할 때까지 기다려야 합니다.
  • 따라서 각 트랜잭션는
    • 읽기/쓰기 허용, 또는
    • 읽기/쓰기를 실행하는 것이 안전할 때까지 지연됩니다.

Examples

S-LOCK(A) :

B:

if LOCK(A) = "unlocked" then
    {
        LOCK(A) ← "read-locked";
        no-of-reads(A) ← 1;
    }
else if LOCK(A) = "read-locked" then
    no-fo-reads(A) ← no-of-reads(A) + 1
else    / i.e., LOCK(A) = "write-locked" /
    {
        Wait until LOCK(A) = "unlocked" and the lock manager
        wakes up the transaction;
        go to B
    }

X-LOCK(A)

B:

if LOCK(A) = "unlocked" then
    LOCK(A) ← "write-locked";
else    / i.e., LOCK(A) = “write locked” or “read” locked /
    {
        Wait until LOCK(A) = “unlocked” and the lock manager
        wakes up the transaction; 
        go to B
    }

UNLOCK(A)

if LOCK(A) = “write-locked” then  
    {
        LOCK(A)  “unlocked”;
        Wake up one of the transactions (if any)   
    }
else if LOCK(A) = “read-locked” then
    {      
        no_of_reads(A)  no-of-reads(A) - 1
        if no_of_reads(A) = 0 then 
            {		  
                LOCK(A) = “unlocked”;
                Wake up one of the transactions (if any)
            }
    }

Basic Locking Protocol

모든 데이터 항목 A에 대해 모든 트랜잭션 T는 다음 규칙을 따라야 합니다.

  • T는 READ(A)가 T에서 수행되기 전에 S-LOCK(A)(또는 X-LOCK(A))을 요청해야 합니다.
  • T는 WRITE(A)(또는 READ(A))가 T에서 수행되기 전에 X-LOCK(A)를 요청해야 합니다.
  • T는 요청 lock(A에 대한)이 다른 트랜잭션이 보유한 다른 잠금과 호환되지 않는 경우 기다려야 합니다.
  • T에서 모든 READ(A)와 WRITE(A)가 완료된 후 T는 UNLOCK(A)를 요청해야 한다.

Example

  • Consistency constraint : A = B

T1

READ(A)
A = A + 100
WRITE(A)
READ(B)
B = B + 100
WRITE(B)

T2

READ(A)
A = A * 2
WRITE(A)
READ(B)
B = B * 2
WRITE(B)
  • basic locking protocol을 따른 transactions

T1

X-LOCK(A)
READ(A)
A = A + 100
WRITE(A)
UNLOCK(A)
X-LOCK(B)
READ(B)
B = B + 100
WRITE(B)
UNLOCK(B)

T2

X-LOCK(A)
READ(A)
A = A * 2
WRITE(A)
UNLOCK(A)
X-LOCK(B)
READ(B)
B = B * 2
WRITE(B)
UNLOCK(B) 
  • 이런 locking protocol은 serializable schedule을 보장할 수 있는가?
    • 다음은 이를 위반하는 예제 이다.

image

  • 이 schedule은 직렬화할 수 없습니다(B(=150)의 최종 값이 잘못되었습니다). T1이 너무 일찍 잠금을 해제한 것 같습니다!

Two-Phase Locking(2PL) Protocol

모든 트랜잭션은 기본 잠금 프로토콜을 따라야 합니다. 또한 모든 트랜잭션에서 모든 잠금은 모든 잠금 해제 요청보다 우선합니다.

이는 두 단계로 구성됩니다.

  • 1단계: 잠금(=확장) 단계
    • 새로운 잠금을 획득했지만 아무 것도 해제할 수 없습니다.
  • 2단계: 잠금 해제(=축소) 단계
    • 기존 잠금을 ​​해제할 수 있지만 새 잠금을 얻을 수 없습니다.
  • 트랜잭션은 필요한 모든 항목에 대한 잠금을 한 번 획득할 때까지 잠금을 해제할 수 없습니다.
  • 트랜잭션은 잠금을 해제하면 추가 잠금을 요청할 수 없습니다.

image

  • 2PL scheduel은 first unlocks에 따른 serial 트랜잭션 순서와 conflict equivalent합니다. 이는 트랜잭션이 축소 단계에 들어가는 순서를 의미합니다.
  • schdule의 모든 트랜잭션이 2PL을 따르는 경우 conflict serializable합니다. 2PL은 오늘날 대부분의 데이터베이스 시스템에서 사용되는 동시성 제어입니다.

Example 1

T1

READ(A)
A = A + 100
WRITE(A)
READ(B)
B = B + 100
WRITE(B)

T2

READ(A)
A = A * 2
WRITE(A)
READ(B)
B = B * 2
WRITE(B)
  • 2PL protocol을 따른 transactions

T1

X-LOCK(A)
X-LOCK(B)
READ(A)
A = A +100
WRITE(A)
UNLOCK(A)
READ(B)
B = B + 100
WRITE(B)
UNLOCK(B)

T2

X-LOCK(A)
X-LOCK(B)
READ(A)
A = A * 2
WRITE(A)
UNLOCK(A)
READ(B)
B = B * 2
WRITE(B)
UNLOCK(B)

image

  • 이제 스케줄 A는 serial 스케줄 T2 다음에 T1이 오는 것과 같기 때문에 conflict-serializable 합니다.

Example 2

T1

READ(A)
A = A + 100
WRITE(A)
READ(B)
B = B + 100
WRITE(B)

T2

READ(A)
A = A * 2
WRITE(A)
READ(B)
B = B * 2
WRITE(B)
  • 2PL protocol을 따른 transactions

T1

X-LOCK(A)
READ(A)
A = A +100
WRITE(A)
X-LOCK(B)
UNLOCK(A)
READ(B)
B = B + 100
WRITE(B)
UNLOCK(B)

T2

X-LOCK(A)
READ(A)
A = A * 2
WRITE(A)
X-LOCK(B)
UNLOCK(A)
READ(B)
B = B * 2
WRITE(B)
UNLOCK(B)

image

  • 스케줄 B는 T1이 뒤따르는 serial 스케줄 T2와 동일하기 때문에 conflict-serializable 합니다.

Performance Degraded

  • 2PL은 동시성의 양을 제한할 수 있습니다.
  • 2PL은 이기적입니다. 장기 transaction에 유리할 수 있습니다.
  • T1이 A, B, C, D, E, . . , 순차적으로, T2는 B에 액세스합니다.

image

  • 이 시점에서 T2가 B에 대한 잠금을 요청하나 거부되었습니다.
  • T2는 T1이 모든 항목 C, D, E에 대한 모든 잠금을 해제할 때까지 기다려야 합니다…
  • T1이 이미 항목 B에 대한 쓰기 작업을 완료했더라도 T1은 잠금을 해제할 수 없습니다.

Deadlocks

  • T1은 T2가 A에 대한 잠금을 해제하기를 기다리고 있고, T2는 T1이 B에 대한 잠금을 해제하기를 기다리고 있습니다.
  • T1은 B에 대한 잠금을 해제할 수 없습니다. T2는 또한 A에 대한 잠금을 해제할 수 없습니다.
  • 다른 트랜잭션도 A 또는 B에 액세스할 수 없습니다.

image

  • Deadlock: 서로의 잠금이 해제되기를 기다리는 트랜잭션의 주기입니다. 어느 거래도 진행할 수 없으며 영원히 기다립니다.
  • Deadlock를 처리하는 두 가지 방법:
    • Deadlock 방지(prevention)
    • Deadlock 감지(detection)

Deadlock Prevention : Timestamp

  • 각 트랜잭션이 시작될 때 타임스탬프를 제공합니다.
  • 이전 트랜잭션의 타임스탬프가 더 작습니다. 최근 트랜잭션이 더 큽니다.
  • 작은 타임스탬프가 큰 것보다 우선 순위가 높습니다.
  • Ti가 Tj가 보유하고 있는 충돌 잠금을 요청한다고 가정합니다.
    • Wait-Die : 비선점
      • Ti의 우선 순위가 더 높으면 Ti는 Tj를 기다립니다.
      • 그렇지 않으면 Ti가 중단되고 나중에 다시 시작됩니다.
    • Wound-Wait : 선점
      • Ti의 우선 순위가 더 높으면 Tj가 중단되고 나중에 다시 시작됩니다.
      • 그렇지 않으면 Ti가 기다립니다.
  • 트랜잭션이 다시 시작되면 원래 타임스탬프를 제공합니다.

Deadlock Prevention : Conservative 2PL

  • 읽기 세트와 쓰기 세트를 미리 선언하여 트랜잭션이 실행을 시작하기 전에 액세스하는 모든 항목을 잠그려면 트랜잭션이 필요합니다.

image

  • 미리 선언된 항목 중 잠글 수 없는 항목이 있는 경우 트랜잭션은 항목을 잠그지 않습니다. 모든 항목을 잠글 수 있을 때까지 기다립니다.

  • 잠금 경합이 심한 경우 보수적인 2PL은 평균적으로 잠금이 유지되는 시간을 줄일 수 있습니다. 잠금을 유지하는 트랜잭션은 차단되지 않습니다.

Deadlock Detection : Wait-For Graph

  • 대기 그래프 생성
    • 각 트랜잭션에 대해 노드를 생성합니다. Ti가 Tj를 기다리고 있는 경우 Ti에서 Tj까지 간선을 만듭니다.
    • 시스템은 교착 상태를 주기적으로 확인합니다. 결과 그래프에 주기가 있으면 교착 상태가 발생한 것입니다!
  • 피해자 선정
    • 교착 상태를 해제하려면 주기에 있는 트랜잭션을 선택하고 중단하십시오.
    • 최소 비용의 거래를 희생양으로 선택합니다. (즉, 가장 적은 잠금, 가장 적은 작업, 완료에서 가장 먼 등)
    • 항상 동일한 트랜잭션이 희생자로 선택되면 기아(starvation)가 발생합니다.
    • 기아를 피하기 위해 중단 횟수를 계산합니다.

image

댓글남기기