포스트

(RDBMS - 5) 동시성 제어(Concurrency Control)

데이터베이스에서 동시성을 제어하는 방법


1. 동시성 제어(Concurrency Control)

동시성 제어(concurrency control)에 대해서 알아보자.


데이터베이스는 보통 다수의 사용자를 가정한다. 따라서 동시에 작동하는 다중 트랜잭션의 상호 간섭 작용에서 데이터베이스를 보호할 수 있어야 하며, 이를 동시성 제어 (Concurrency Control)라고 한다.

  • 동시성을 제어할 수 있도록 하기 위해 모든 DBMS가 공통적으로 Lock 기능을 제공한다. 여러 사용자가 데이터를 동시에 액세스하는 것처럼 보이지만 내부적으로는 하나씩 실행되도록 트랜잭션을 직렬화(Serialize)하는 것이다.
  • SET TRANSACTION 명령어를 이용해 트랜잭션의 격리 수준(Isolation level)을 조정할 수 있는 기능도 제공한다.
    • 데이터베이스마다 구현 방식이 다르지만 SQL Server를 예로 들면, 기본 트랜잭션 Isolation level인 Read Committed 상태에선 레코드를 읽고 다음 레코드로 이동하자마자 Shared Lock을 해제하지만, Repeatable Read로 올리면 트랜잭션을 Commit될 때까지 Shared Lock을 유지한다.


격리 수준(Isolation level), 락(Lock)에 대한 개념은 뒤의 포스트에서 다룬다.



2. 스케쥴, 직렬화 가능(Schedule, Serializability)

이전의 ACID에서의 Isolation에서 이용한 예제를 다시 이용하겠다.

AB에게 20만원을 이체할 때 B가 동시에 ATM에서 자기 계좌로 30마원을 입금하는 상황이라고 가정하자. 이때 이 트랜잭션이 가능한 여러 형태의 동작을 케이스 별로 살펴보자.


Case 1

mysql



Case 2

mysql



Case 3

mysql



Case 4

mysql

  • Case 4의 경우 Bbalance를 이미 read한 상황에서 30만원 입금에 대한 Transaction2가 일어난 후, 기존의 Transaction1에서 읽은 balance에 대해서 write 작업이 실행되면서 기존의 30만원 입금이 사라졌다
  • Case 4의 경우를 Lost Update라고 하며, 뒤의 Isolation Level에서 더 자세히 살펴볼 예정


위의 4가지 케이스에 대해서 각 read, write, commit을 하나의 연산(operation)이라고 하고, 이를 간략화 해서 표현해보자.

  • 예) Trasnsaction1에 대한 A의 잔액 read : read(A_balance)r1(A)


이런식으로 일련의 연산들을 나열해서 다음과 같이 표현할 수 있다.

  • Case 1 : r1(A) w1(A) r1(B) w1(B) c1 r2(A) w2(B) c2
  • Case 2 : r2(B) w2(B) c2 r1(A) w1(A) r1(B) w1(B) c1
  • Case 3 : r1(A) w1(A) r2(B) w2(B) c2 r1(A) w1(A) c1
  • Case 4 : r1(A) w1(A) r1(B) r2(B) w2(B) c2 w1(B) c1


일련의 연산을 수행하는 방법들은 위의 4가지 케이스 말고도 더 다양하게 존재할 수 있다. 이 연산들을 수행하는 순서를 Schedule이라고 한다. 이 떄 각 트랜잭션내의 연산들에 대한 순서는 바뀌지 않는다.

  • 예) Transaction2r2(B) w2(B) c2 라는 순서 자체는 변하지 않는다


다음으로 Schedule이 짜여진 형태에 따라 어떻게 분류되는지 알아보자.


mysql

  • Serial Schedule: 트랜잭션들이 겹치지 않고 한 번에 하나씩 실행되는 Schedule
  • Non-Serial Schedule: 트랜잭션들이 동시에 겹쳐서 실행되는 Schedule


Schedule의 개념에 대해 더 자세히 알아보자.



2.2 Serial Schedule

mysql

  • Serial Schedule는 이상한 데이터가 만들어질 가능성은 없다
  • Serial Schedule의 경우 한번에 하나의 트랜잭션만을 실행하기 때문에 성능이 좋지 않아서 현실적으로 사용할 수 없는 방식
    • 동시성이 없기 때문에 여러 트랜잭션을 처리할 수 없음



2.3 Non-Serial Schedule

mysql

  • Non Serial Schedule의 경우 트랜잭션들이 겹쳐서 실행되기 때문에 같은 시간 동안 더 많은 트랜잭션의 처리가 가능하다
  • 우리가 앞에서 봤던 Schedule 4 처럼 트랜잭션이 어떤 형태로 겹쳐져서 실행되나에 따라 이상한 결과(Lost Update)가 나올 수 있다.



3. Conflict

결론적으로, 우리는 동시에 많은 트랜잭션들을 겹쳐서 (Non Serial Schedule) 실행할 수 있으면서 이상한 결과는 나오지 않도록 하고 싶다. 이를 달성하기 위해서, 우리는 Serial Schedule과 동일한 Non Serial Schedule을 이용하면 되는것이다.

여기서 Serial Schedule과 동일한 Non Serial Schedule 이라는 모순적인 표현을 설명하기 위해서 “Schedule이 동일하다” 가 무엇을 의미하는지 Conflict의 개념을 통해 설명할 것이다.


두 개의 operation이 다음의 3 가지 조건을 만족하면 Conflict라고 부른다.

  1. 서로 다른 트랜잭션 소속
  2. 같은 데이터(리소스)에 접근
  3. 최소 하나는 write operation


mysql

  • Conflict Operation은 순서가 바뀌면 결과가 바뀐다
  • 위의 2read-write conflict의 operation 순서를 바꾸면 기존의 결과와 달라지는 것을 확일 할 수 있다.


Conflict가 무엇인지 알았으니 Conflict Equivalent가 무엇인지 알아보자.

두 개의 Schedule이 다음의 두 조건을 만족하면 서로 conflict equivalent라고 한다.


  1. Schedule은 같은 트랜잭션들을 가진다
  2. 어떠한 Conflict Operation의 순서도 두 Schedule 모두 동일하다


mysql

여기서 그림에서 볼 수 있듯이 schedule2serial schedule이고, schedule3의 입장에서 schedule2conflict equivalent 한 것이다. 여기서 serial scheduleconflict equivalent 한 경우 이를 Conflict Serializable이라고 한다.

즉, non-serial scheduleschedule3Conflict Serializableschedule이고, 이 때문에 non-serial schedule임에도 불구하고 정상적인 결과를 가질 수 있었던 것이다.


반면에 schedule4의 경우에는 serial schedule과 비교해서 Conflict Operation들의 순서가 동일하지 않기 때문에 Conflict Equivalent 하다고 볼 수 없다. 그리고 그 어떤 serial schedule(schedule1,2Conflict Equivalent하지 않기 때문에 이상한 결과가 나온다고 볼 수 있다.


정리하자면,

  1. A schedule which is conflict equivalent (view equivalent) with a serial schedule is conflict serializable (has conflict serializibility, or view serializable)
  2. Concurrency control makes any schedule serializable



4. Conflict Serializability Protocol

위에서도 언급했던것 처럼 우리의 목표는Non Serial Schedule을 실행할 수 있으면서 이상한 결과는 나오지 않도록 하고 싶었고. 이를 달성하기 위해서 Serial Schedule과 동일한 Non Serial Schedule을 구현하고 싶어했다.

여기서 Serial Schedule과 동일한 Non Serial Schedule은 결국에 Conflict Serializablenon-serial schedule을 구현하면 되는 것이다.

이런 schedule을 구현하기 위해서 사용하는 방법은 무엇일까?


정답은 여러 트랜잭션을 동시에 실행해도 scheduleconflict serializable하도록 보장하는 프로토콜(Protocol)을 사용하는 것이다. 이런 프로토콜을 구현하기 위해 각 RDBMS는 Isolation Level, Locking, Concurrency control mechanisms, Conflict detection, etc.. 여러가지 전략들을 사용할 수 있다.



5. Recoverability

Recoverability에 대해서 알아보자.


5.1 Unrecoverable Schedule

이전의 이체 예시에서 다음과 같은 새로운 schedule5를 이용해보자.

mysql

  • 위의 경우 CommitTransaction1에서 RollbackTransaction2에서 write 했던 230만원을 read 했다. 즉 유효하지 않은 데이터를 읽어서 작업을 한 것이다.


Schedule내에서 Commit된 트랜잭션이 Rollback된 트랜잭션이 write했던 데이터를 읽었을 경우 이런 scheduleUnrecoverable Schedule이라고 부른다.

Unrecoverable Schedule의 경우, Rollback을 해도 이전 상태로 회복이 불가능하기 때문에 이런 schedule은 DBMS가 허용하면 안된다.



5.2 Recoverable Schedule

그럼 Unrecoverable과 반대되는 Recoverable Schedule이 뭔지 알아보자.


mysql

  • Transaction1Transaction2를 의존하기 떄문에 의존성이 있는 트랜잭션이 먼저 Commit 되면 안됨
  • T2Rollback하는 경우 T1Rollback하면 됨


여기서 Recoverable Scheduleschedule 내에서 그 어떤 트랜잭션도 자신이 읽은 데이터를 write한 트랜잭션이 먼저 Commit/Rollback 하기 전까지는 Commit하지 않는 schedule을 의미한다.

이런 scheduleRollback을 할 때 이전 상태로 온전히 돌아갈 수 있기 때문에 DBMS는 Recoverable Schedule만 허용해야 한다.



5.3 Cascadeless Schedule

하나의 트랜잭션이 Rollback을 하면 의존성이 있는 다른 트랜잭션도 Rollback을 해야한다. 바로 이전의 상황을 이용하자면, T2Rollback하는 경우, T2에 의존성이 있는 T1Rollback 해야한다. 이 처럼 연쇄적으로 Rollback이 일어나는 것을 Cascading Rollback이라고 한다. Cascading Rollback의 경우 많이 일어나면 이를 처리하기 위한 비용이 많이 든다.

이런 Cascading Rollback의 문제를 해결하기 위해서 데이터를 write한 트랜잭션이 Commit/Rollback 한 뒤에는 데이터를 읽는 schedule만을 허용하는 방법이 나온다.


mysql

  • Transaction2Rollback이 되어도, 아무것도 일어나지 않았던 것 처럼 그냥 Transaction1을 진행하면 된다


이 처럼 schedule 내에서 어떠한 트랜잭션도 Commit 되지 않은 트랜잭션들이 write한 데이터는 읽지 않았을 경우, Cascadless Schedule이라고 한다.



5.4 Strict Schedule

바로 이전에 봤던 Cascadeless Schedule도 문제는 존재한다. 예를 들자면, 피자가게에서 원래 피자가격인 3만원을 1만원으로 변경하는 트랜잭션을 Transaction1, 2만원으로 변경하는 트랜잭션을 Transaction2라고 하자.

schedule : write1(pizza = 10000) write2(pizza = 20000) commit2 abort

여기서 Transaction1이 문제가 생겨 abort하게 된 경우이다. 이 경우 Transaction1이 시작하기 이전으로 되돌리기 때문에 피자가격이 3만원으로 다시 변하면서, Transaction2에 대한 결과가 완전히 사라지게 된다.

Cascadeless Schedule의 정의를 다시 살펴보자. Cascadeless Schedule는 스케쥴내에서 어떠한 트랜잭션도 커밋되지 않은 트랜잭션들이 write한 데이터를 읽지 않은 스케쥴을 의미한다. 위의 예시는 읽기 작업이 없기 때문에 Cascadeless Schedule이라고 할 수 있다. 이런 Cascadeless Schedule의 문제를 해결하기 위해서는 추가적으로 Commit 되지 않은 트랜잭션들이 write한 데이터를 쓰지도 읽지도 않아야 한다. 이런 스케쥴을 Strict Schedule이라고 한다.

다시 한번 Strict Schedule의 정의를 살펴보자.

Strict Scheduleschedule 내에서 어떠한 트랜잭션도 Commit 되지 않은 트랜잭션들이 write한 데이터는 읽지도 쓰지도(read or write) 않았을 경우의 schedule을 의미한다.


mysql

https://levelup.gitconnected.com/the-schedule-in-the-dbms-2d8c6f19720d


지금까지 다룬 내용을 결론 내자면 다음과 같다.

Concurrency control provides Serializability and Recoverability.


Reference

  1. 한국 데이터 산업 진흥원 - SQL 전문가 가이드

  2. 인프런 쉬운코드 - 데이터베이스

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.

Comments powered by Disqus.