컴퓨터공학/데이터베이스

[데이터베이스] 병행 제어

NIMHO 2022. 11. 30. 14:47
728x90

복습하기 위해 학부 수업 내용을 필기한 내용입니다.
이해를 제대로 하지 못하고 정리한 경우 틀린 내용이 있을 수 있습니다.
그러한 부분에 대해서는 알려주시면 정말 감사하겠습니다.

트랜잭션

ex. A 계좌에서 100원을 B계좌로 이체하는 트랜잭션

T:	Read(A)
	A = A - 100
	Write(A)
	Read(B)
	B = B + 100
	Write(B)

실행 도중 장애 발생

A 계좌 100원 인출, B계좌 입금 실패 시 모순 상태(inconsistent state) 발생

둘 다 수행되거나, 하나라도 수행되지 않아야 한다.

DBMS는 어느 부분이 트랜잭션인지 알 수 없다.

사용자가 트랜잭션을 명시적으로 표시해야 한다.

 

트랜잭션이란?

일련의 연산들의 집합니다.

하나의 논리적 기능을 수행하기 위한 작업의 단위로서 데이터베이스의 일관된 상태또 다른 일관된 상태로 변환시킨다.

이를 위해 트랜잭션에 포함된 모든 연산은 완전히 처리되거나 하나도 처리되지 않아야 한다.(All or Nothing방식)

Begin_Trans
	...
	...
End_Trans

 

트랜잭션의 특성(ACID)

원자성(Atomicity)전부 또는 전무(All or Nothing) 실행만 한다.

 

일관성(Consistency)트랜잭션 실행 후에도 일관성이 유지되어야 한다.

 

격리성(Isolation)트랜잭션 실행 중 연산의 중간 결과에 다른 트랜잭션이 접근할 수 없다.

 

영속성(Durability)트랜잭션이 일단 성공적으로 실행되면 그 결과는 영구적이다.

 

트랜잭션의 원자성

트랜잭션 T

계좌 A에서 100원을 계좌 B에 이체한다.

계좌 A의 잔액 = 1000, B의 잔액 = 2000이라고 가정한다.

트랜잭션 실행 후 계좌 A와 B의 합계는 변하면 안 된다.

T:	Begin_Trans
		Read(A)
		A = A - 100
		Write(A)
		Read(B)
		B = B + 100
		Write(B)
	End_Trans

 

장애 발생 시

트랜잭션 T를 실행하는 도중 장애 발생

데이터 항목 A만 디스크에 출력되고 B는 디스크에 출력되지 못하였을 경우

→ 디스크의 데이터베이스에 있는 계좌 : A = 900, B = 2000

 

장애의 결과로 100을 상실

T의 실행 전후가 달라져 일관성 제약을 위반하게 된다.

트랜잭션 설정은 이러한 모순 상태(inconsistent state)를 방지할 수 있다.

 

트랜잭션의 원자성을 위한 연산

Commit(완료)

트랜잭션이 성공적으로 실행되었다는 것을 선언

일관성 있는 데이터베이스 상태로 변환되었을 경우

갱신된 데이터의 값이 영속성을 갖도록 보장되어야 한다.

 

Rollback(복귀)

트랜잭션의 실행이 실패했다는 것을 선언

모순된 데이터베이스 상태

수행한 모든 연산의 결과는 원상 복귀시켜야 한다.

 

트랜잭션의 상태

활동(active)

트랜잭션이 실행을 시작한다.

 

부분 완료(partially committed)

마지막 명령문을 실행시킨 직후의 상태이다.

 

실패(failed)

실행 중에 장애나 오류 발생하여 비 정상적인 상태이다.

 

철회(aborted)

실행을 실패하여 Rollback 연산을 수행한 상태, 트랜잭션을 재시작하거나 강제 종료시켜야 한다.

 

완료(committed)

실행을 성공적으로 완료하여 commit 연산을 수행한 상태, DB에 저장되어 연속성 보장한다.

병행 제어

복수 사용자 DBMS에서는 병행 수행(concurrency)을 지원한다.

프로그램 P1, P2가 인터리브(interleave) 형태로 병행한다.

병행 수행의 문제점

1) 갱신 분실 (lost update)

2) 모순성 (inconsistency)

3) 연쇄 복귀 (cascading rollback)

 

1) 갱신 분실 (Lost Update)

T2만 갱신한 결과가 되고, T1의 갱신 연산은 무효가 된다.

 

2) 모순성 (Inconsistency)

T1만 하면 200, 200 / T2만 하면 200, 200

T1 → T2 : 400, 400

T2  T1 : 300, 300

하지만 저런 경우에는 400, 300으로 사용자가 원하는 연산 결과가 나오지 않는다.

 

3) 연쇄 복귀 (Cascading Rollback)

T1 : y를 판독하여 갱신하려다 문제가 발생해, 갱신을 취소하고 원래 상태로 복귀한다.

T2 : 당연히 복귀해야 하지만, 이미 완료된 상태이다.

 

트랜잭션 스케줄

직렬 스케줄(serial schedule)

트랜잭션 별로 연속적으로 실행하는 스케줄이다.

단, 값비싼 CPU의 낭비가 발생한다.

 

직렬 가능 스케줄(serializable schedule)

비직렬 스케줄이지만 정확한 결과를 생성한다.

현실적으로 스케줄의 직렬 가능성 검사는 매우 어렵다.

 

병행 제어(concurrency control) 기법

로킹(locking), 타임스탬프(timestamp)

 

로킹 기법

여러 트랜잭션들이 같은 항목에 대해 임의적인 병행 접근을 하지 못하게 하는 것이다.

 

타임스탬프

타임스탬프 순서에 따라 실행되게 하는 것이다.

하지만 현재는 잘 사용하지 않는다.

 

로킹 기법

1. lock-S : 공용 로크(shared-lock)

트랜잭션 T는 read 할 수 있지만, write는 할 수 없다.

이때 다른 트랜잭션은 공동 lock을 동시에 걸 수 있다.

 

2. lock-X : 전용 로크(exclusive-lock)

T는 read와 write 모두 할 수 있다.

이때 다른 트랜잭션은 어떤 lock도 걸 수 없다.

 

Lock의 양립성(Compatibility)

 

로킹 규약을 따랐음에도 모순성이 발생한 예

x=100, y=200이라 하면

T1 → T2 : x=400, y=600

T2 → T1 : x=300, y=500

실행 결과: x=400, y=500

 

이유: 트랜잭션 T1 이 너무 일찍 unlock(x)를 실행

T1 → T2, T2 → T1, T1 → T2 → T1

어떻게 흐름이 이어지더라도 다 같아야 한다.

 

2단계 로킹 규약

2PL : Two Phase Locking protocol

1) 확장 단계(growing phase)

rock만 할 수 있고, unlock은 할 수 없는 단계이다.

 

2) 축소 단계(shrinking phase)

unlock만 할 수 있고, lock은 할 수 없는 단계이다.

 

[정리]

스케줄 내의 모든 트랜잭션들이 2단계 로킹 규약(2PL)을 준수한다면 그 스케줄은 직렬 가능하다.

(즉, 정확한 결과를 생성한다.)

 

ex. 2PLP로 직렬 가능한 스케줄

단, 교착 상태(deadlock)가 발생할 수 있다.

 

교착 상태(Deadlock)

아무도 Unlock을 할 수 없고 영원히 기다리는 상태가 된다.

[그림 14-11]

728x90

해결 방법 : 회피(avoidance), 예방(prevention), 탐지(detection)

회피

자원을 할당할 때마다 deadlock이 일어나지 않도록 실시간 알고리즘을 사용한다.(현실성 X)

 

예방

트랜잭션을 실행시키기 전에 필요한 lock을 한꺼번에 모두 요청전부 부여받지 못하면 실행시키지 않는다.(현실성 X)

 

탐지

lock 상태를 조사해 일단 교착상태가 탐지되면 한 트랜잭션을 취소시켜 다시 스케줄을 실행한다.

(취소시킬 트랜잭션은 작업이 가장 적게 수행된 트랜잭션이 설정되는 것이 효율적이다.)

 

회피 방법

교착 상태 회피 방법 : 타임스탬프 이용한다.

타임스탬프는 트랜잭션이 기다려야 할지 복귀해야 할지를 결정하는 데 사용된다.

 

wait-die 기법

트랜잭션 Ti가 이미 트랜잭션 Tj가 lock한 데이터 항목을 요구할 때

만일 Ti의 타임스탬프가 Tj의 타임스탬프 보다 작을 경우(즉, Ti가 고참인 경우) Ti를 기다리게(wait) 하고,

그렇지 않으면(즉, Ti가 신참인 경우) Ti는 포기(die)했다가 나중에 같은 스탬프를 가지고 다시 시작한다.

 

[그림 14-11]

트랜잭션 T1은 이미 트랜잭션 T2가 lock 한 데이터 y를 요구한다.

이때 트랜잭션 T1의 타임스탬프는 T2의 타임스탬프보다 작으므로(즉, T1이 고참이므로) T1을 기다리게 (wait) 한다.

 

wound-wait 기법

트랜잭션 Ti가 이미 트랜잭션 Tj가 lock 한 데이터 항목을 요구할 때

만일 Ti의 타임스탬프가 Tj의 타임스탬프보다 작을 경우(즉, Ti가 고참인 경우)

Ti는 데이터를 선점(wound) 한다. 그렇지 않으면(즉, Ti가 신참인 경우) Ti를 기다리게(wait)한다.

 

[그림 14-11]

고참인 T1은 데이터를 선점(wound) 한다.

 

예방 방법

트랜잭션을 실행시키기 전에 필요한 lock을 한꺼번에 모두 요청하여 전부 부여받지 못하면 실행시키지 않는다.

그러나 데이터 요구에 대한 사전 지식을 필요로 하기 때문에 현실성이 없어 보인다.

또한, 데이터 항목이 한꺼번에 lock 되기에 상당한 기간 동안 데이터가 실제로 사용되지 않을 수 있다.

따라서, 데이터 항목의 활용도가 매우 낮아지게 된다.

 

탐지 방법

교착 상태를 탐지하는 간단한 방법은 대기 그래프(wait for graph)를 사용하는 것이다.

현재 T2가 lock 한 데이터 항목 y를 T1이 lock 하기 위해 기다리고 있으면 방향 간선 T1 → T2로 표현한다.

이런 방식으로 구축된 대기 그래프에 사이클(cycle)이 생기면 교착 상태가 발생했다고 판단한다.

교착 상태가 탐지되면 트랜잭션들 중 하나를 선택하여 실행을 취소시켜 사이클을 제거해야 되는데,

이때 취소시킬 트랜잭션은 작업이 가장 적게 수행된 트랜잭션이 선정되는 것이 효율적이다.

 

 

로킹 단위(locking granularity)

로킹의 대상이 되는 데이터 객체의 크기를 말하는데 이는 병행 제어의 데이터 단위가 된다.

일반적으로 로킹 단위가 클수록 병행성 수준이 낮아지는 반면에 병행 제어 기법은 간단해진다.

반대로 로킹 단위가 작을수록 병행성 수준은 높아지지만 lock의 수가 많아지게 되어 관리가 복잡해진다.

극단적으로 로킹 단위가 데이터베이스 전체가 된다면 병행성은 전혀 없게 된다.

 

적절한 로킹 단위의 결정은 시스템 성능 향상을 위한 하나의 중요한 요소가 될 수 있다.

지금까지 배운 모든 예시는 데이터 항목만을 로킹 단위로 고려했다.

만일 데이터 항목 단위로만 lock를 한다면 모든 항목에 대해 lock 연산을 실행해야되어서 많은 로킹 연산이 필요하다.

비효율성을 해결하기 위해서 여러 종류(레코드, 파일, 데이터베이스 등)의 로킹 단위를 지원할 수 있는

다중 단 위 로킹(multiple granularity locking) 기법이 필요하다.

728x90