이 글을 읽기전 동시성 제어의 사전지식과 동시성 제어를 해야하는 이유에 대해 먼저 보고 오시는것을 추천드립니다.
동시성 제어(Concurrency Control)
동시성 제어(Concurrency Control)란, 여러 사용자나 프로세스가 데이터를 공유할 때 발생할 수 있는 문제를 해결하기 위해, 데이터베이스 시스템이 트랜잭션을 순서대로 실행하는 것이 아니라, 트랜잭션이 동시에 실행될 수 있도록 허용하면서도 데이터의 일관성과 무결성을 유지할 수 있도록 하는 기술이며, 데이터베이스 시스템에서 매우 중요한 개념 중 하나입니다.
동시성 제어의 목적
- 여러 사용자가 DB에 접근하더라도 데이터의 일관성을 보장하고 데이터의 무결성을 유지
- 위를 만족하며 데이터베이스 시스템의 성능과 효율성을 유지하는 것
동시성 제어 기법
1. Locking
- 정의
Locking은 한 번에 하나의 트랜잭션이 데이터를 수정할 수 있도록 하는 방법입니다.
즉, 하나의 트랜잭션이 실행되는 동안 특정 데이터 항목에 대해서 다른 트랜잭션은 동시에 접근할 수 없도록 상호 배제 기능을 제공합니다.
- 잠금에 대한 연산
- Locking의 종류
1. Shared Locks (공유 잠금)
공유잠금을 설정한 트랜잭션은 데이터 항목에 대해 읽기 연산만 가능합니다.
여러 트랜잭션이 읽기만 하는 경우 다른 트랜잭션들과 공유하여 사용할 수 있습니다. 예를 들어, 테이블 A의 데이터를 읽는 트랜잭션 1과 2가 동시에 실행 중일 때, 둘 다 데이터에 Shared Lock을 걸어 읽을 수 있습니다. 이 때 다른 트랜잭션들은 읽기 작업만 가능하고 수정 작업은 불가능합니다.
즉, T1이 S-Locks을 설정했을때 unlock 전에 T2가 동일 데이터에 접근한다면 읽기만 가능하게 됩니다.
2. Exclusive Locks (배타적 잠금)
X-Locks를 설정한 트랜잭션은 데이터 항목에 대해 읽기 연산과 쓰기 연산이 모두 가능합니다.
하나의 트랜잭션만이 획득할 수 있으며, 획득한 트랜잭션이 해당 데이터를 수정할 때(unlock)까지 다른 트랜잭션들은 대기해야 합니다. X-Lock은 다른 Lock들과 충돌이 발생하며, 다른 트랜잭션이 이미 S-Lock을 획득한 상황에서는 X-Lock을 요청할 수 없습니다. 만약 X-Lock이 이미 다른 트랜잭션에 의해 획득되어 있다면, 다른 트랜잭션들은 해당 Lock이 해제될 때까지 대기해야 합니다.
X-Lock은 트랜잭션의 일관성을 유지하기 위한 중요한 요소 중 하나입니다. 트랜잭션 A가 특정 데이터를 수정하기 위해 X-Lock을 획득하고, 이 작업이 완료되면 해당 Lock을 해제합니다. 이후 트랜잭션 B가 동일한 데이터를 수정하기 위해 X-Lock을 획득할 수 있습니다. 이러한 과정을 통해 데이터 일관성을 보장할 수 있습니다.
- 잠금 설정 규칙(Locking Protocol)
잠금 설정 규칙(Locking Protocol)은 동시성 제어를 위해 데이터베이스 시스템에서 채택하는 규칙입니다. 이 규칙은 여러 개의 트랜잭션이 데이터베이스에 접근할 때, 데이터의 일관성과 동시성을 보장하기 위해 잠금(락)을 설정하는 방식을 규정합니다.
위 그림처럼 T14와 T15를 동시에 실행할때 T14에서 write(x)연산을 하고 x-lock(y)연산을 하기 전에 T15가 실행되면 T15는 S-lock(y)는 정상적으로 얻게되지만 S-lock(x)는 T14에서 잠가놓았기 때문에 얻을 수 없고 대기상태로 들어가게 됩니다. 하지만 T14 또한 X-lock(y) 연산을 진행하려 하지만 T15에서 잠가놨기 때문에 마찬가지로 대기상태에 들어가게 되며, T14와 T15 모두 대기상태에 계속 빠지게 됩니다. 이러한 상황을 교착상태라 합니다.
이러한 상황에 빠지지 않도록 여러 규약들이 나왔습니다.
1. Two-Phase Locking Protocol (2PL)
2PL은 데이터베이스에서 동시성 제어를 위해 사용되는 가장 기본적인 잠금 기법 중 하나입니다. 이 프로토콜은 모든 트랜잭션이 두 단계로 나뉘어서 작동하도록 보장합니다.
- 확장 단계 : 트랜잭션은 lock 연산만 수행할 수 있고 unlock 연산은 수행할 수 없습니다. 이 단계에서 다른 트랜잭션은 해당 데이터 항목에 대한 Lock을 획득 할 수 없습니다.
- 축소 단계 : 트랜잭션은 unlock 연산만 수행할 수 있고 lock 연산은 수행할 수 없습니다.
2PL 프로토콜은 두 단계 모두에서 잠금을 보유하는 동안, 다른 트랜잭션이 같은 데이터 항목에 대해 충돌을 유발하는 잠금을 요청하면 대기해야 합니다. 이렇게 함으로써, 데이터베이스는 모든 트랜잭션에서 충돌을 방지하고 일관성을 유지할 수 있습니다.
하지만 위 그림이 2PL을 준수했지만 DeadLock에 빠진 상황입니다.
2. Strict Two-Phase Locking Protocol (Strict 2PL)
현재 대부분의 DBMS에서 사용하는 규약으로 Strict 2PL은 모든 잠금 요청을 트랜잭션의 commit 혹은 abort까지 보류하는 것을 말합니다. 이로써 트랜잭션이 다른 트랜잭션의 작업에 끼어들지 않도록 보장하며, Deadlock을 예방합니다. 그러나 트랜잭션이 데이터 항목을 잠그고 있는 동안 다른 트랜잭션은 해당 데이터 항목에 대한 Lock을 요청할 수 없으므로, 처리 속도가 저하될 수 있습니다. Strict 2PL은 다음 단계로 나뉘어서 작동합니다.
- Growing Phase: 트랜잭션이 처음으로 데이터 항목에 접근할 때 Shared Lock을 요청합니다. Shared Lock을 요청하다가 거부된 경우, 트랜잭션은 rollback됩니다.
- Shrinking Phase: 트랜잭션이 데이터 항목의 작업을 완료한 후, Shared Lock을 release하기 전에 Exclusive Lock을 요청합니다. Exclusive Lock을 요청하다가 거부된 경우, 트랜잭션은 rollback됩니다.
- Commit Phase: 트랜잭션이 모든 데이터 항목에 대한 Exclusive Lock을 release하고 commit합니다.
즉, 모든 X-lock의 unlock 연산을 트랜잭션이 완전히 완료된 후에 실행하는 것입니다.
이렇게 하면 완료되지 않은 트랜잭션에 의해 갱신된 데이터를 다른 트랜잭션이 읽거나 쓸 가능성을 원천적으로 봉쇄할 수 있어 연쇄 복귀 문제를 해결할 수 있습니다.
Locking 기법의 장단점
장점 :
- 데이터의 일관성 유지: Locking은 여러 트랜잭션이 동시에 데이터에 접근하는 것을 제어하여 데이터의 일관성을 유지합니다.
- 무결성 보호: Locking은 데이터의 무결성을 보호하기 위해 사용됩니다. 동시에 여러 사용자가 같은 데이터를 변경하면 데이터의 일관성이 깨질 수 있습니다. 이를 방지하기 위해 Locking을 사용하여 동시에 여러 사용자가 데이터를 변경할 수 없도록 제어합니다.
- 복잡한 동시성 제어 알고리즘이 필요하지 않습니다.
단점 :
- 데드락: 여러 트랜잭션이 데이터에 대해 서로 다른 Lock을 보유하고 있는 경우 데드락이 발생할 수 있습니다. 이 경우 Lock을 해제하기 위해 트랜잭션을 롤백하거나 중단해야 할 수 있습니다.
- 처리 속도 감소: Locking은 여러 트랜잭션이 데이터에 접근하는 것을 제어하기 때문에 처리 속도가 느려질 수 있습니다. 특히 Exclusive Lock을 사용하는 경우, 다른 트랜잭션이 해당 데이터에 접근할 때까지 대기해야 하기 때문입니다.
- 교착상태 위험: 여러 트랜잭션이 데이터에 대해 서로 다른 Lock을 보유하고 있는 경우 교착상태가 발생할 수 있습니다. 이 경우 모든 트랜잭션을 롤백하거나 중단해야 할 수 있습니다.병행성 감소: Locking은 동시에 여러 트랜잭션이 데이터를 액세스하지 못하도록 제어하기 때문에 병행성이 감소할 수 있습니다. 특히 Exclusive Lock을 사용하는 경우, 데이터에 대한 동시 액세스가 제한됩니다.
2. Timestamp 기법
Timestamp 기법은 데이터베이스 동시성 제어 기법 중 하나입니다. 이 기법은 각 트랜잭션마다 타임스탬프를 할당하고, 데이터베이스에 저장된 데이터의 타임스탬프와 비교하여 동시성을 제어하는 방식입니다.
1) Read timestamp
Read timestamp는 데이터베이스의 MVCC (Multi-Version Concurrency Control) 기법 중 하나로, 트랜잭션이 읽은 데이터의 최신 버전을 판단하기 위해 사용되는 타임스탬프입니다.
특정 트랜잭션이 데이터를 읽을 때, 그 시점에 읽힌 데이터의 버전을 알기 위해 해당 트랜잭션의 시작 시점에 할당된 타임스탬프와 데이터의 버전 정보를 비교합니다. 이를 통해 해당 트랜잭션이 읽은 데이터의 버전이 현재의 최신 버전인지 판단하고, 이를 기반으로 다음 동작을 수행합니다.
예를 들어, 트랜잭션 T1이 테이블의 행 A를 읽을 때, T1이 시작된 시점에 할당된 타임스탬프를 사용하여 A의 버전 정보와 비교합니다. 만약 A의 버전 정보가 T1이 읽은 시점에 이미 업데이트 되어 최신 버전이 아니라면, T1은 해당 버전의 데이터를 참조하지 않고 다시 최신 버전의 데이터를 읽도록 시도합니다.
2) Write timestamp
Write timestamp는 데이터베이스의 MVCC (Multi-Version Concurrency Control) 기법 중 하나로, 트랜잭션이 데이터를 변경할 때, 새로운 데이터의 버전을 판단하기 위해 사용되는 타임스탬프입니다.
특정 트랜잭션이 데이터를 변경할 때, 해당 트랜잭션의 시작 시점에 할당된 타임스탬프를 사용하여 새로운 버전을 생성합니다. 그리고 이 버전 정보를 데이터와 함께 저장하며, 이를 Write timestamp라고 합니다.
예를 들어, 트랜잭션 T2가 테이블의 행 B를 변경할 때, T2가 시작된 시점에 할당된 타임스탬프를 사용하여 B의 새로운 버전을 생성합니다. 그리고 이 버전 정보를 B와 함께 저장합니다. 이후, 다른 트랜잭션이 B를 읽을 때, Read timestamp와 비교하여 최신 버전을 판단하게 됩니다.
3) Commit timestamp
Commit timestamp은 트랜잭션이 커밋된 시간을 의미합니다. 모든 트랜잭션은 커밋될 때 새로운 timestamp 값을 부여받습니다. Commit timestamp은 해당 트랜잭션을 다른 트랜잭션과 구분하기 위한 용도로 사용됩니다.
Commit timestamp을 사용하면 두 개 이상의 트랜잭션이 동일한 데이터를 갱신할 때 발생할 수 있는 갱신 분실 문제를 방지할 수 있습니다. 예를 들어, 트랜잭션 A와 B가 동일한 데이터를 갱신하고 A가 B보다 먼저 커밋되었다면, B의 변경 내용은 무시됩니다.
또한 Commit timestamp은 데이터베이스에서 복구 작업을 수행할 때 유용합니다. 데이터베이스가 비정상적으로 종료되거나 시스템 장애가 발생할 경우, Commit timestamp을 사용하여 마지막으로 커밋된 트랜잭션 이후의 변경 내용만을 복구할 수 있습니다.
따라서, Commit timestamp은 데이터베이스의 데이터 일관성과 복구 기능에 매우 중요한 역할을 합니다.
이러한 방식의 timestamp 기법은 트랜잭션 간 충돌을 최소화하면서 동시성 제어를 달성합니다. 하지만 시스템 시간의 정확성을 보장할 수 없기 때문에, 대부분의 데이터베이스에서는 다른 기법과 함께 사용됩니다. 또한, timestamp 기법은 일반적으로 쓰기 작업이 많은 시스템에서 성능이 저하될 수 있습니다.
Timestamp 기법의 장단점
장점 :
- 높은 동시성: 트랜잭션 간에 Lock 경합이 없으므로 동시에 많은 트랜잭션을 처리할 수 있습니다.
- 교착상태 방지: 트랜잭션마다 timestamp를 부여하고 순서에 따라 lock을 걸어 교착상태를 방지할 수 있습니다.
- 시간 기반 처리: timestamp 기반이므로 시간적 순서를 보장하며, 응용 프로그램이 시간을 기반으로 데이터를 처리해야 할 때 유용합니다
단점 :
- 시스템 오버헤드: 모든 트랜잭션에 timestamp를 부여하고 비교해야 하므로 시스템의 오버헤드가 발생할 수 있습니다.
- 시간 동기화 필요: 각 서버나 클라이언트 시스템의 시간을 동기화시켜야만 정확한 결과를 보장할 수 있습니다.
- Non-repeatable read: 한 트랜잭션에서 읽은 데이터를 다른 트랜잭션이 갱신했을 경우, 해당 트랜잭션에서 다시 읽었을 때 이전과 다른 값을 얻을 수 있습니다.
- Rollback 발생 가능성이 높습니다.
3. Multi-Version Concurrency Control 기법
MVCC는 각 트랜잭션에서 일어나는 읽기와 쓰기 연산을 다른 트랜잭션의 영향을 받지 않고 실행할 수 있도록 해주며, 트랜잭션들이 동시에 데이터베이스에 접근하여 변경 작업을 수행할 때 발생할 수 있는 문제를 해결합니다.
MVCC가 데이터베이스에서 데이터를 읽을 때 해당 데이터의 버전(혹은 스냅샷)을 생성하여 이 버전을 기반으로 읽기 연산을 수행합니다. 쓰기 연산을 수행할 때는 새로운 버전을 생성하고, 새 버전에 대한 포인터를 이전 버전에 대한 포인터와 함께 저장합니다. 이를 통해 새로운 버전이 생성되어도 이전 버전을 이용하여 읽기 연산을 수행할 수 있습니다.
MVCC는 각 트랜잭션의 시작 시점에 트랜잭션 ID와 해당 시점의 스냅샷 버전이 할당됩니다. 이후 읽기 연산이 수행될 때는 트랜잭션 ID와 스냅샷 버전을 기반으로 데이터를 읽습니다. 만약 해당 데이터의 버전이 현재 트랜잭션의 스냅샷 버전보다 더 최신 버전이라면, 이 데이터는 다른 트랜잭션에 의해 변경된 데이터이므로 해당 트랜잭션은 롤백됩니다. 이와 같은 방식으로 MVCC는 트랜잭션의 격리성(isolation)을 보장합니다.
MVCC는 대부분의 상황에서 우수한 성능을 보입니다. 하지만, 데이터베이스에서 데이터의 변경 빈도가 매우 높거나, 데이터를 업데이트하는 트랜잭션이 많은 경우에는 MVCC의 성능이 저하될 수 있습니다. 또한 MVCC는 각 트랜잭션의 시작 시점에 스냅샷을 생성하는데, 이 때문에 스냅샷 생성에 대한 오버헤드가 발생할 수 있습니다.
MVCC의 장점
- 동시성: MVCC는 여러 사용자가 데이터를 동시에 액세스할 수 있도록 하면서 데이터의 일관성과 무결성을 보장합니다.
- 격리 수준: MVCC는 데이터베이스의 격리 수준을 유지하면서 동시성 문제를 해결합니다.
- 공간 효율성: MVCC는 복사본을 만들어 현재 버전의 데이터를 변경합니다. 이전 버전의 데이터는 남아 있지만, 필요할 때만 액세스할 수 있으므로 공간 효율적입니다.
- 성능: MVCC는 데이터를 읽을 때 락을 걸지 않기 때문에 성능이 향상됩니다. 또한 복사본을 만드는 것이 추가 오버헤드를 일으킬 수 있지만, 일반적으로 복사본을 만드는 것은 상대적으로 저렴합니다.
MVCC는 다중 사용자 데이터베이스 환경에서 동시성 문제를 해결하는 데 매우 효과적인 방법입니다.
MVCC의 단점
- 더 많은 저장 공간이 필요하다: MVCC는 매번 새로운 버전을 생성하기 때문에, 데이터베이스 저장 공간이 더 많이 필요하게 됩니다. 또한, 각 버전은 이전 버전과 연결되어 있으므로 불필요한 데이터의 중복이 발생할 수 있습니다.
- 인덱스의 복잡성 증가: MVCC를 구현하는 데는 인덱스가 필요합니다. 이 인덱스는 레코드의 버전 정보를 저장해야 하므로 인덱스의 복잡성이 증가합니다.
- 롤백 비용 증가: 롤백은 이전 버전으로 복구되는 것이므로, 롤백이 발생할 경우에는 많은 비용이 소모됩니다. 이는 많은 양의 데이터가 변경된 경우에는 매우 비싼 작업이 될 수 있습니다.
- 동시성 제어 부하 증가: MVCC를 사용하면 두 개 이상의 트랜잭션이 같은 데이터를 읽을 때 버전 충돌이 발생합니다. 이러한 충돌을 해결하기 위해 데이터베이스 시스템은 많은 추가 작업을 수행해야 하므로, 시스템의 부하가 증가합니다. 따라서, 고성능 트랜잭션 처리가 필요한 경우 MVCC는 적합하지 않을 수 있습니다.
'CS 지식' 카테고리의 다른 글
2022년 3회 정보처리기사 실기 기출문제 (0) | 2023.07.19 |
---|---|
2022년 2회 정보처리기사 실기 기출문제 (1) | 2023.07.16 |
2022년 1회 정보처리기사 실기 기출문제 (0) | 2023.07.16 |
동시성 제어(Concurrency Control)가 필요한 이유 (0) | 2023.03.13 |