[CS Study] Database - Concurrency Control

Frye 'de Bacon·2023년 12월 18일
0

Computer Science(CS)

목록 보기
32/40

동시성 제어(Concurrency Control)

동시성 제어의 정의

동시성 제어(Concurrent control)란 여러 개의 트랜잭션이 작업을 성공적으로 마칠 수 있도록 트랜잭션의 실행 순서를 제어하는 기법을 말한다.

조금 더 자세히 정의하면 다음과 같이 정리할 수 있다.

  • 다중 사용자 환경을 지원하는 데이터베이스 시스템에서 여러 트랜잭션들이 성공적으로 동시에 실행될 수 있도록 지원하는 기능
  • 다중 사용자 환경을 지원하는 데이터베이스 시스템의 경우 필수적으로 지원하는 기능으로서, 병행제어라고도 한다.
  • 트랜잭션의 직렬화 수행을 보장한다.

여기서 '다중 사용자 환경'이란 여러 명의 사용자가 동시에 DB에 접근하여 데이터를 조회하거나 조작하는 환경을 말한다.

동시성 제어의 목적

동시성 제어는 다음과 같은 목적을 가진다.

  • 트랜잭션의 직렬성 보장
  • 공유도 최대, 응답 시간 최소, 시스템 활동의 최대 보장
  • 데이터의 무결성 보장

데이터의 무결성

데이터의 무결성이란 데이터의 정확성, 일관성, 유효성이 유지되는 것을 의미한다.

  • 데이터의 정확성 : 데이터의 중복이나 누락이 없는 상태
  • 데이터의 일관성 : 원인과 결과의 의미가 연속적으로 보장되어 변하지 않는 상태

동시성 제어를 하지 않을 경우 발생하는 문제점

갱신 손실(Lost update)

하나의 트랜잭션이 갱신한 내용을 다른 트랜잭션이 덮어씀으로써 갱신이 무효가 되는 것을 의미한다. 두 개 이상의 트랜잭션이 하나의 데이터를 동시에 갱신(Update)할 때 발생한다.
다음과 같이 동시에 진행되는 두 개의 트랜잭션 T1과 T2의 예를 살펴보자.

T1T2X와 Y의 값
read_item(X);
X = X - 100,000;
-X = 300,000
Y = 600,000
-read_item(X);
X = X + 50,000;
X = 300,000
Y = 600,000
write_item(X);
read_item(Y);
-X = 200,000
Y = 600,000
-write_item(X);
X = 350,000
Y = 600,000
Y = Y + 100,000;
write_item(Y);
-X = 350,000
Y = 700,000

본래 정상적으로 수행되었다면(즉, T1이 수행된 후 T2가 수행되거나 혹은 그 반대의 순으로 수행되었다면) X의 최종 값은 25만 원, Y의 최종 값은 70만 원이 되어야 한다. 그러나 트랜잭션이 동시에 수행되어 T1이 수정한 값을 T2가 덮어씀으로써 T1의 X 갱신이 손실되는 갱신 손실이 발생하였다.

현황 파악 오류(Dirty read)

두 트랜잭션이 동일한 데이터에 접근했을 때, 트랜잭션 T1이 작업을 하는 도중 다른 트랜잭션 T2가 해당 데이터를 읽고, 작업 중이었던 T1이 rollback을 함으로써 데이터 갱신을 무효화하면 T2는 무효가 된 데이터를 읽게 됨으로써 잘못된 결과가 도출된다. 연쇄 복귀(Cascading rollback)라고도 한다.
※ 앞서 트랜잭션 포스트에서도 간단히 설명한 내용이다.

다시 예를 통해 이해해 보자.

T1T2
UPDATE account
SET balance = balance - 100,000
WHERE cust_name = "김날로";
-
-SELECT AVG(balance)
FROM account;
ROLLBACK;-
-COMMIT;

T1이 account 테이블에서 '김날로'의 잔액 데이터를 10만 원 감소시키는 작업을 진행하던 도중 T2가 account 테이블의 잔액 데이터를 전부 읽어 평균을 계산하였다(따라서 T2가 계산한 평균치는 10만원 감소된 '김날로'의 잔액이 반영되어 있다). 그런데 T1이 수행했던 작업을 rollback함으로써 '김날로'의 잔액이 복원되고, 결국 T2의 작업은 틀린 계산값이 된다. 이를 현황 파악 오류 혹은 연쇄 복귀라 한다.

반복 불가능한 조회(Non-repeatable read)

동일한 트랜잭션 내에서 같은 데이터를 여러 번 조회했을 때 조회한 데이터의 값이 서로 다른 경우를 의미한다. 위의 '김날로' 잔액 데이터를 다시 예로 들어 보자.

T1T2
-SELECT AVG(balance)
FROM account;
UPDATE account
SET balance = balance - 100,000
WHERE cust_name = "김날로";
COMMIT;
-
-SELECT AVG(balance)
FROM account;
COMMIT;

T2가 전체 계좌의 평균 잔액을 2차례 계산하는 사이에 T1이 '김날로'의 잔액 데이터를 변경하였다. 따라서 T2가 처음 계산한 평균값과 두 번째로 계산한 평균값은 달라지게 된다.

비슷한 원리로 조회한 결과의 행이 새로 생기거나 아예 없어지는 팬텀 리드(Phantom read) 현상이 발생하기도 한다.

모순성(Inconsistency)

모순성, 혹은 불일치 분석이란 다른 트랜잭션들이 데이터를 갱신하는 동안 한 트랜잭션이 두 항목 중 어떤 것은 갱신되기 전의 값을, 어떤 것은 갱신한 후의 값을 읽게 되어 데이터의 불일치가 발생하는 현상을 말한다.

다시 예를 통해 확인해 보자. 최초 X와 Y의 값은 모두 10만 원이라고 가정한다.

T1T2X와 Y의 값
read_item(X);
X = X + 100,000;
write_item(X);
-X = 200,000
Y = 100,000
-read_item(X);
X = X * 2
write_item(X);
read_item(Y);
Y = Y * 2;
write_item(Y);
X = 400,000
Y = 200,000
read_item(Y);
Y = Y + 100,000;
write_item(Y);
-X = 400,000
Y = 300,000

상기 예의 경우 T1은 X와 Y에 각각 10만 원씩을 추가하는 작업을 진행하고 있고, T2는 X와 Y의 값에 2를 곱하는 작업을 수행하고 있다. 만약 T1, T2의 순으로 트랜잭션이 수행되었다면 X와 Y의 값은 모두 40만 원이 되어야 하고, T2, T1의 순으로 트랜잭션이 수행되었다면 X와 Y의 값은 모두 30만 원이 되어야 한다. 그러나 T1과 T2가 동시에 수행되면서 이와 같은 모순성이 나타나는 것이다.


동시성 제어 방법

Locking

하나의 트랜잭션이 실행되는 동안 특정 데이터 항목에 대하여 다른 트랜잭션이 접근하지 못하도록 상호배제(Mutual exclusive) 기능을 제공하는 기법이다. 즉, 트랜잭션이 데이터에 잠금(lock)을 설정하여 다른 트랜잭션은 잠금이 해제(unlock)될 때까지 해당 데이터에 대하여 접근/수정/삭제하지 못하도록 하는 방법이다.

잠금은 크게 두 가지 종류로 나눌 수 있다.

구분내용
Shared lock
(S-lock)
데이터 항목에 대해 읽기 연산(read)만 가능한 잠금
다른 트랜잭션도 읽기 연산만을 수행 가능
하나의 데이터에 대하여 여러 개의 S-lock이 가능
Exclusive lock
(X-lock)
데이터 항목에 대해 읽기 연산(read)과 쓰기 연산(write)이 모두 가능
다른 트랜잭션은 읽기와 쓰기가 모두 불가
하나의 데이터에 대하여 하나의 X-lock만 가능

※ 사실 이 외의 잠금도 존재하나 여기서는 이 두 가지만 짚고 넘어간다. 자세한 내용은 DB Lock 참조

잠금과 관련하여 몇 가지 개념을 이해하고 넘어가는 것이 도움이 된다.

  1. 잠금 설정 규칙
  • 트랜잭션은 데이터 항목 X에 대하여 read(X) 연산을 실행하기 전 S-lock(X) 혹은 X-lock(X) 중 하나를 실행해야 한다.
  • write(X) 연산을 실행하기 위해서는 X-lock(X)을 실행해야 한다.
  • 연산 종료 후에는 unlock(X)을 실행해야 한다.
  • unlock(X) 연산은 S-lock(X) 혹은 X-lock(X)을 실행한 후에만 실행할 수 있다.
  1. 잠금 단위(Locking granularity)
    잠금 단위란 잠금의 대상이 되는 데이터 객체의 크기를 말한다. 작게는 레코드의 필드 값부터 레코드, 블록 등이 될 수 있으며 크게는 테이블 전체나 DB 전체까지도 하나의 잠금 단위가 될 수 있다.
    이때 잠금 단위가 클수록 동시성(병행성) 수준은 낮아지고 동시성 제어 기법은 간단해진다. 반대로 잠금 단위가 작을수록 동시성 수준은 높아지고 동시성의 관리는 복잡해진다.

    예컨대 잠금 단위가 레코드라면 두 개의 트랜잭션이 하나의 테이블에 대해 현산을 수행하더라도 접근하는 레코드가 다를 경우 동시 실행이 가능하다. 다만 접근하는 레코드마다 잠금을 설정해야 하므로 관리는 복잡해진다.
    반대로 잠금 단위가 테이블일 경우 여러 트랜잭션이 동시에 실행되는 것은 불가능하지만, 테이블 하나에만 잠금을 설정하면 되므로 관리는 쉬워진다.

따라서 잠금 단위를 여러 단계로 설정하고 필요에 따라 혼용하는 방식이 많이 사용된다.

  1. 2단계 잠금 프로토콜(2-Phase Locking protocol, 2PL)
    2PL은 잠금을 크게 '잠금 설정 단계'와 '잠금 해제 단계'의 두 가지로 나누어 수행하는 것이다.

    구분내용
    확장 단계(Growing phase)트랜잭션이 lock 연산만 수행 가능하고 unlock 연산은 수행 불가능한 단계
    축소 단계(Shrinking phase)트랜잭션이 unlock 연산만 수행 가능하고 lock 연산은 수행 불가능한 단계

    2PL은 데이터 오류 가능성을 사전에 예방하며, 직렬 가능한 스케줄을 항상 보장할 수 있다. 그러나 교착 상태(Deadlock) 문제가 발생할 수 있는데, 이를 해결하는 가장 간단한 방법은 트랜잭션의 시작 전 필요한 모든 잠금을 동시에 설정하는 것이다. 혹은 교착 상태 회피 방법이나 탐지 방법 등을 활용할 수도 있다.

    2PL은 연쇄 복귀 문제(Dirty read)도 발생할 수 있는데, 이는 엄격한 2PL(Strict 2PL)로 해결 가능하다. 2PL에서는 lock을 조금씩 해제할 수도 있고, 트랜잭션이 완료 시점에 이르렀을 때 모든 lock을 한꺼번에 해제할 수도 있는데, 모든 lock을 한 번에 해제하는 방법이 바로 엄격한 2PL이다. 현재 대부분의 DBMS에서는 이 방법을 이용하여 동시성 제어를 구현하고 있다.

Timestamp

타임스탬프는 각각의 트랜잭션을 식별하기 위해 DBMS가 부여하는 유일한 식별자를 말한다. 타임스탬프 기법은 이 타임스탬프를 이용하여 트랜잭션 간의 순서를 미리 선택하는 방법이다.

타임스탬프는 시스템에 들어오는 트랜잭션에 순차적으로 타임스탬프를 지정하고 이를 동시성 제어의 기준으로 사용한다. 이를 이용해 교착상태를 방지할 수 있다. 다만 rollback의 발생률이 높고 연쇄 복귀 문제도 야기할 수 있다.

타임스탬프는 크게 두 가지 방법을 이용해 부여한다.

구분내용
논리적 계수기 사용법트랜잭션이 시스템에 들어올 때 계수기(counter)의 값을 하나씩 증가시키면서 타임스탬프를 생성
시스템 시계 사용법트랜잭션이 시스템에 들어올 때의 시스템 시계(System clock)을 적용하여 타임스탬프를 생성

Validation

적합성 검증(Validation) 또는 낙관적 검증 기법은 트랜잭션이 수행되는 동안은 어떠한 검증도 수행하지 않고, 트랜잭션이 종료되었을 때 일괄적으로 검사하는 방법이다. 트랜잭션이 수행되는 동안은 데이터 항목들의 메모리상 사본에 대해서만 갱신을 실시하고, 트랜잭션 종료 후 동시성을 위한 트랜잭션 직렬화가 검증된 경우에만 일시에 DB에 해당 갱신 내용을 반영하는 것이다.

적합성 검증 시에는 트랜잭션의 실행을 크게 셋으로 나눈다.

구분내용
판독 단계
(Read phase, R)
트랜잭션 작업 구역에 지역 사본을 만들어 읽기와 갱신을 수행
검증 단계
(Validation phase, v)
실제 데이터베이스에 반영하기 전 충돌 직렬 가능성 검사
기록 단계
(Write phase, W)
검증 단계를 통과한 트랜잭션의 실행 결과는 실제로 데이터베이스에 반영하고, 통과하지 못한 트랜잭션은 취소 후 재시작

그리고 각 트랜잭션에는 3가지의 타임스탬프를 사용한다.

구분내용
Start(TiT_{i})트랜잭션 TiT_{i}가 판독 단계에 들어가면서 판독을 시작한 시간
Validation(TiT_{i})트랜잭션 TiT_{i}가 판독 단계를 끝내고 검증을 시작한 시간
Finish(TiT_{i})트랜잭션 TiT_{i}가 최종 기록 단계를 완료한 시간

적합성 검증 기법의 경우 트랜잭션의 길이가 길다면 트랜잭션이 실행되다 rollback되었을 때 자원이 낭비되는 기법이다. 따라서 동시 사용 빈도가 낮은 시스템에서 주로 사용된다.


참고 자료

profile
AI, NLP, Data analysis로 나아가고자 하는 개발자 지망생

0개의 댓글