회복과 병행 제어

회복과 병행 제어

회복과 병행 제어

트랜잭션 관리를 통한 데이터베이스의 일관성 유지, 장애 회복, 병행 제어를 다룬다.


1. 트랜잭션

1.1 트랜잭션의 개념

트랜잭션(Transaction) 은 작업 하나를 수행하는 데 필요한 데이터베이스 연산들의 모임으로, 논리적인 작업의 단위다.

┌─────────────────────────────────────────────────────────┐
│                     트랜잭션 예시                         │
│                    (계좌 이체)                           │
├─────────────────────────────────────────────────────────┤
│  BEGIN TRANSACTION                                      │
│    1. A계좌에서 10,000원 출금  (UPDATE)                   │
│    2. B계좌에 10,000원 입금    (UPDATE)                   │
│  COMMIT (또는 ROLLBACK)                                 │
└─────────────────────────────────────────────────────────┘
          ↓
   모두 성공하거나, 모두 취소되어야 함 (All or Nothing)

1.2 트랜잭션의 특성 (ACID)

특성영문설명DBMS 기능
원자성Atomicity모두 수행되거나, 하나도 수행되지 않아야 함회복 기능
일관성Consistency수행 전후 데이터베이스가 일관된 상태 유지병행 제어
격리성Isolation수행 중인 트랜잭션의 중간 결과에 다른 트랜잭션 접근 불가병행 제어
지속성Durability완료된 트랜잭션 결과는 영구적으로 보존회복 기능
┌─────────────────────────────────────────────────────────────┐
│                    ACID 특성 시각화                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   [원자성]          [일관성]          [격리성]          [지속성] │
│       │                │                 │                │   │
│   All or            일관된              독립적           영구적  │
│   Nothing           상태유지            수행             보존   │
│       │                │                 │                │   │
│       └────────────────┴─────────────────┴────────────────┘   │
│                              │                               │
│                    ┌─────────┴─────────┐                     │
│                    │  회복 기능        │  병행 제어 기능       │
│                    │ (원자성, 지속성)  │ (일관성, 격리성)      │
│                    └───────────────────┘                     │
└─────────────────────────────────────────────────────────────┘

1.3 트랜잭션의 연산

연산설명
COMMIT트랜잭션이 성공적으로 완료됨을 선언 (작업 완료)
ROLLBACK트랜잭션 수행이 실패했음을 선언 (작업 취소)
-- 트랜잭션 예제: 계좌 이체
BEGIN TRANSACTION;

UPDATE 계좌 SET 잔액 = 잔액 - 10000 WHERE 계좌번호 = 'A001';
UPDATE 계좌 SET 잔액 = 잔액 + 10000 WHERE 계좌번호 = 'B001';

-- 모든 연산이 성공하면
COMMIT;

-- 오류 발생 시
-- ROLLBACK;

1.4 트랜잭션의 상태

┌─────────────────────────────────────────────────────────────────┐
│                     트랜잭션 상태 전이도                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│                         ┌──────────┐                            │
│                         │  활동    │ ←── 트랜잭션 시작           │
│                         │ (Active) │                            │
│                         └────┬─────┘                            │
│                              │                                  │
│              ┌───────────────┼───────────────┐                  │
│              │               │               │                  │
│              ▼               │               ▼                  │
│       ┌──────────┐           │        ┌──────────┐              │
│       │ 부분완료  │           │        │   실패   │              │
│       │(Partially│           │        │ (Failed) │              │
│       │Committed)│           │        └────┬─────┘              │
│       └────┬─────┘           │             │                    │
│            │                 │             │ rollback           │
│            │ commit          │             ▼                    │
│            ▼                 │      ┌──────────┐                │
│     ┌──────────┐             │      │   철회   │                │
│     │   완료   │             │      │(Aborted) │                │
│     │(Committed)│            │      └──────────┘                │
│     └──────────┘             │             │                    │
│            │                 │             │                    │
│            └─────────────────┴─────────────┘                    │
│                        트랜잭션 종료                             │
└─────────────────────────────────────────────────────────────────┘
상태설명
활동(Active)트랜잭션이 수행을 시작하여 현재 수행 중인 상태
부분 완료(Partially Committed)마지막 연산이 실행된 직후 상태 (아직 DB 반영 전)
완료(Committed)commit 연산 실행, 결과가 DB에 반영된 상태
실패(Failed)장애로 인해 수행이 중단된 상태
철회(Aborted)rollback 연산 실행, 트랜잭션 이전 상태로 복귀

2. 장애와 회복

2.1 장애의 유형

유형설명원인
트랜잭션 장애트랜잭션 수행 중 오류 발생논리적 오류, 잘못된 데이터 입력, 자원 부족
시스템 장애하드웨어 결함으로 수행 중단메인 메모리 정보 손실, 교착 상태
미디어 장애디스크 장치 결함디스크 헤드 손상, 고장

2.2 저장 장치의 종류

┌─────────────────────────────────────────────────────────────┐
│                     저장 장치 계층                           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   ┌─────────────────┐                                       │
│   │   휘발성 저장장치  │  장애 시 데이터 손실                  │
│   │   (메인 메모리)   │  속도: 빠름                          │
│   └────────┬────────┘                                       │
│            │ input/output                                   │
│            ▼                                                │
│   ┌─────────────────┐                                       │
│   │  비휘발성 저장장치 │  장애 시에도 데이터 유지              │
│   │   (디스크, SSD)  │  단, 저장장치 자체 고장 시 손실 가능   │
│   └────────┬────────┘                                       │
│            │ dump                                           │
│            ▼                                                │
│   ┌─────────────────┐                                       │
│   │   안정 저장장치   │  복사본 다중 보관                     │
│   │  (RAID, 백업)    │  어떤 장애에도 데이터 보존             │
│   └─────────────────┘                                       │
│                                                             │
└─────────────────────────────────────────────────────────────┘

2.3 데이터 이동 연산

┌─────────────────────────────────────────────────────────────────┐
│                     데이터 이동 연산                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ┌──────────────┐     read(X)      ┌──────────────┐            │
│   │  프로그램    │ ◄──────────────── │   메인메모리  │            │
│   │   변수      │                   │  버퍼 블록    │            │
│   │             │ ────────────────► │              │            │
│   └──────────────┘     write(X)     └──────┬───────┘            │
│                                            │                    │
│                                   input(X) │ ▲ output(X)        │
│                                            ▼ │                  │
│                                    ┌──────────────┐             │
│                                    │    디스크    │             │
│                                    │  디스크 블록  │             │
│                                    └──────────────┘             │
│                                                                 │
│   • input(X): 디스크 → 메인메모리                                │
│   • output(X): 메인메모리 → 디스크                               │
│   • read(X): 버퍼 블록 → 프로그램 변수                           │
│   • write(X): 프로그램 변수 → 버퍼 블록                          │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

2.4 회복 기법

복사본 생성 방법

방법설명
덤프(Dump)데이터베이스 전체를 주기적으로 다른 저장 장치에 복사
로그(Log)변경 연산마다 이전 값과 이후 값을 별도 파일에 기록

회복 연산

연산설명사용 시점
redo(재실행)로그를 이용해 변경 연산을 재실행DB 전반적으로 손상된 경우
undo(취소)로그를 이용해 변경 연산을 취소변경 중인 내용만 손상된 경우

로그 레코드의 종류

┌─────────────────────────────────────────────────────────────────┐
│                       로그 파일 예시                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   <T1, start>                      ← T1 시작                    │
│   <T1, A, 1000, 950>               ← T1이 A를 1000에서 950으로   │
│   <T1, B, 2000, 2050>              ← T1이 B를 2000에서 2050으로  │
│   <T1, commit>                     ← T1 완료                    │
│   <T2, start>                      ← T2 시작                    │
│   <T2, C, 500, 400>                ← T2가 C를 500에서 400으로    │
│   <checkpoint [T2]>                ← 검사 시점 (T2 수행 중)      │
│   <T2, D, 300, 350>                ← T2가 D를 300에서 350으로    │
│   <T2, commit>                     ← T2 완료                    │
│   <T3, start>                      ← T3 시작                    │
│   <T3, E, 100, 80>                 ← T3가 E를 100에서 80으로     │
│   ────── 장애 발생 ──────                                       │
│                                                                 │
│   → T3는 commit 없음 → undo 필요                                │
│   → T2는 checkpoint 이후 commit → redo 필요                     │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

로그 회복 기법 비교

구분즉시 갱신 회복지연 갱신 회복
DB 반영 시점트랜잭션 수행 중 즉시 반영부분 완료 후 한 번에 반영
로그 기록<Ti, X, old, new><Ti, X, new>
장애 시 (commit 전)undo 연산로그 무시 (버림)
장애 시 (commit 후)redo 연산redo 연산
┌────────────────────────────────────────────────────────────────────────┐
│                   즉시 갱신 vs 지연 갱신 비교                            │
├────────────────────────────────────────────────────────────────────────┤
│                                                                        │
│   [즉시 갱신]                        [지연 갱신]                         │
│                                                                        │
│   트랜잭션 시작                      트랜잭션 시작                        │
│       │                                 │                              │
│       ▼                                 ▼                              │
│   ┌───────┐                         ┌───────┐                          │
│   │로그기록│                         │로그기록│                          │
│   └───┬───┘                         └───┬───┘                          │
│       │                                 │                              │
│       ▼                                 │ (DB 반영 없음)                │
│   ┌───────┐                             │                              │
│   │DB 반영│ ← 즉시 반영                 │                              │
│   └───┬───┘                             │                              │
│       │                                 │                              │
│       ▼                                 ▼                              │
│   ┌───────┐                         ┌───────┐                          │
│   │commit │                         │commit │                          │
│   └───┬───┘                         └───┬───┘                          │
│       │                                 │                              │
│       │                                 ▼                              │
│       │                             ┌───────┐                          │
│       │                             │DB 반영│ ← 이 시점에 반영          │
│       │                             └───────┘                          │
│       ▼                                 ▼                              │
│   완료                               완료                               │
│                                                                        │
│   장애 시: undo 또는 redo 필요       장애 시: redo만 필요               │
│                                                                        │
└────────────────────────────────────────────────────────────────────────┘

검사 시점(Checkpoint) 회복 기법

로그 전체를 분석하는 비효율성을 해결하기 위해 일정 간격으로 검사 시점을 설정한다.

┌─────────────────────────────────────────────────────────────────────────┐
│                    검사 시점 회복 기법 예시                               │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│   시간 →                                                                │
│   ────────────────────────────────────────────────────────────────►     │
│                                                                         │
│   T1 ├──────────┤                           ← checkpoint 전 완료        │
│                                               (회복 불필요)             │
│                                                                         │
│   T2 ├────────────────────┤                 ← checkpoint 전 시작,       │
│                                               checkpoint 후 완료        │
│                      checkpoint              (redo 필요)               │
│                          │                                              │
│   T3         ├───────────┼──────────┤       ← checkpoint 전 시작,       │
│                          │                    장애 시점에 수행 중       │
│                          │                   (undo 필요)               │
│                          │                                              │
│   T4                     │   ├──────────┤   ← checkpoint 후 완료        │
│                          │                   (redo 필요)               │
│                          │                                              │
│   T5                     │          ├───────── 장애 발생               │
│                          │                   (undo 필요)               │
│                          │                   │                          │
│                          ▼                   ▼                          │
│                    <checkpoint>          장애 발생                      │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

3. 병행 제어

3.1 병행 수행의 개념

병행 수행(Concurrency): 여러 트랜잭션이 동시에 수행되는 것 (인터리빙 방식)

┌─────────────────────────────────────────────────────────────────┐
│                  인터리빙 방식 수행 예시                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   [직렬 수행]                                                   │
│   T1: ████████████████                                          │
│   T2:                 ████████████████                          │
│   시간 →                                                        │
│                                                                 │
│   [병행 수행 - 인터리빙]                                         │
│   T1: ████    ████    ████    ████                              │
│   T2:     ████    ████    ████                                  │
│   시간 →                                                        │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

3.2 병행 수행의 문제점

갱신 분실 (Lost Update)

┌─────────────────────────────────────────────────────────────────┐
│                     갱신 분실 예시                               │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   초기값: X = 100                                               │
│                                                                 │
│   T1                          T2                                │
│   ─────                       ─────                             │
│   read(X)  → X=100                                              │
│                               read(X)  → X=100                  │
│   X = X - 10                                                    │
│   X = 90                                                        │
│                               X = X + 20                        │
│                               X = 120                           │
│   write(X) → X=90                                               │
│                               write(X) → X=120                  │
│                                                                 │
│   결과: X = 120                                                 │
│   문제: T1의 갱신(-10)이 분실됨                                  │
│   기대값: 100 - 10 + 20 = 110                                   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

모순성 (Inconsistency)

┌─────────────────────────────────────────────────────────────────┐
│                      모순성 예시                                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   초기값: X = 100, Y = 100  (합계: 200)                         │
│                                                                 │
│   T1 (X, Y 각각 2배)          T2 (X+Y 합계 계산)                 │
│   ─────                       ─────                             │
│   read(X)  → 100                                                │
│   X = X * 2 = 200                                               │
│   write(X)                                                      │
│                               read(X)  → 200                    │
│                               read(Y)  → 100                    │
│   read(Y)  → 100              합계 = 300  ← 모순!               │
│   Y = Y * 2 = 200                                               │
│   write(Y)                                                      │
│                                                                 │
│   T1 완료 후 올바른 합계: 400                                   │
│   T2가 읽은 합계: 300 (일관성 없는 상태에서 읽음)               │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

연쇄 복귀 (Cascading Rollback)

┌─────────────────────────────────────────────────────────────────┐
│                    연쇄 복귀 예시                                │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   T1                          T2                                │
│   ─────                       ─────                             │
│   read(X)                                                       │
│   X = X - 10                                                    │
│   write(X)                                                      │
│                               read(X)  ← T1이 변경한 X 읽음     │
│                               X = X + 5                         │
│                               write(X)                          │
│   장애 발생!                                                    │
│   ROLLBACK                                                      │
│                               ROLLBACK 필요!  ← 연쇄 복귀       │
│                                                                 │
│   문제: T2가 이미 commit 했다면 rollback 불가능!                │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

3.3 트랜잭션 스케줄

스케줄 유형설명결과 정확성
직렬 스케줄트랜잭션별로 순차 실행 (인터리빙 X)항상 정확
비직렬 스케줄인터리빙 방식으로 병행 수행보장 안됨
직렬 가능 스케줄직렬 스케줄과 동일한 결과를 내는 비직렬 스케줄정확
┌─────────────────────────────────────────────────────────────────────────┐
│                      스케줄 유형 비교                                    │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│   [직렬 스케줄]                                                         │
│   T1: read(A) → write(A) → read(B) → write(B)                           │
│   T2:                                          read(A) → write(A)       │
│   ✓ 정확한 결과 보장                                                    │
│   ✗ 병행성 없음                                                         │
│                                                                         │
│   [비직렬 스케줄 - 직렬 가능]                                            │
│   T1: read(A) → write(A) ─────────────────────→ read(B) → write(B)      │
│   T2:                    read(A) → write(A)                             │
│   ✓ 직렬 스케줄과 동일한 결과                                            │
│   ✓ 병행성 확보                                                         │
│                                                                         │
│   [비직렬 스케줄 - 직렬 불가능]                                          │
│   T1: read(A) ─────────────────→ write(A)                               │
│   T2:          read(A) → write(A)                                       │
│   ✗ 갱신 분실 등 문제 발생 가능                                          │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

3.4 로킹(Locking) 기법

Lock 연산의 종류

연산설명다른 트랜잭션 허용
공용 Lock (S-Lock)read만 가능, write 불가공용 Lock만 허용
전용 Lock (X-Lock)read, write 모두 가능모든 Lock 불허
┌─────────────────────────────────────────────────────────────────┐
│                   Lock 양립성 매트릭스                           │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│              │  공용 Lock (S)  │  전용 Lock (X)  │              │
│   ───────────┼─────────────────┼─────────────────┤              │
│   공용 Lock  │       ✓         │       ✗         │              │
│   ───────────┼─────────────────┼─────────────────┤              │
│   전용 Lock  │       ✗         │       ✗         │              │
│                                                                 │
│   ✓: 양립 가능 (동시에 Lock 획득 가능)                           │
│   ✗: 양립 불가 (대기해야 함)                                     │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

로킹 단위와 병행성

┌─────────────────────────────────────────────────────────────────┐
│                   로킹 단위 트레이드오프                         │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   로킹 단위 ──────────────────────────────────────────►         │
│              작음                              큼               │
│            (속성)    (튜플)    (릴레이션)    (데이터베이스)      │
│                                                                 │
│   병행성      높음 ◄──────────────────────────────► 낮음        │
│   제어복잡도  높음 ◄──────────────────────────────► 낮음        │
│   오버헤드    높음 ◄──────────────────────────────► 낮음        │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

3.5 2단계 로킹 규약 (2PL)

2단계 로킹 규약을 준수하면 직렬 가능성이 보장된다.

단계설명
확장 단계Lock 연산만 가능, Unlock 불가
축소 단계Unlock 연산만 가능, Lock 불가
┌─────────────────────────────────────────────────────────────────────────┐
│                    2단계 로킹 규약 시각화                                │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│   Lock 수                                                               │
│     ▲                                                                   │
│     │          Lock Point                                               │
│     │              ▼                                                    │
│     │         ┌────┐                                                    │
│     │        /      \                                                   │
│     │       /        \                                                  │
│     │      /          \                                                 │
│     │     /            \                                                │
│     │    /              \                                               │
│     │   /                \                                              │
│     │  /                  \                                             │
│     └──────────────────────────────────────────────►  시간              │
│        │ 확장 단계 │    축소 단계   │                                    │
│        │ (Lock만) │   (Unlock만)  │                                    │
│                                                                         │
│   규칙: 첫 번째 Unlock 전에 필요한 모든 Lock을 획득해야 함              │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

2PL 예제

┌─────────────────────────────────────────────────────────────────────────┐
│                      2PL 준수 vs 위반                                   │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│   [2PL 준수]                       [2PL 위반]                           │
│   ─────────                        ─────────                            │
│   lock(A)      ┐                   lock(A)      ┐                       │
│   read(A)      │ 확장              read(A)      │                       │
│   lock(B)      │ 단계              unlock(A)    ┘ ← Unlock 발생         │
│   read(B)      ┘                   lock(B)      ← Lock 시도 (위반!)     │
│   write(A)                         read(B)                              │
│   unlock(A)    ┐ 축소              unlock(B)                            │
│   write(B)     │ 단계                                                   │
│   unlock(B)    ┘                   ✗ 직렬 가능성 보장 안됨              │
│                                                                         │
│   ✓ 직렬 가능성 보장                                                    │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

3.6 교착 상태 (Deadlock)

2PL을 사용해도 교착 상태(Deadlock) 가 발생할 수 있다.

┌─────────────────────────────────────────────────────────────────┐
│                     교착 상태 예시                               │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   T1                              T2                            │
│   ─────                           ─────                         │
│   lock(A)                                                       │
│                                   lock(B)                       │
│   lock(B) ← 대기                                                │
│       │                           lock(A) ← 대기                │
│       │                               │                         │
│       └───────────────────────────────┘                         │
│                   서로 대기 → 교착 상태!                         │
│                                                                 │
│                   ┌─────┐                                       │
│                   │  A  │ ◄─── T1이 Lock                        │
│                   └──┬──┘                                       │
│                      │ T2 대기                                  │
│                      ▼                                          │
│   T1 대기 ──►   ┌─────┐                                         │
│                 │  B  │ ◄─── T2가 Lock                          │
│                 └─────┘                                         │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

교착 상태 해결 방법

방법설명
예방교착 상태가 발생하지 않도록 사전에 조치
탐지교착 상태 발생 시 탐지하여 해결
타임아웃일정 시간 대기 후 자동 롤백

4. 실무 SQL 예제

4.1 트랜잭션 제어

-- MySQL 트랜잭션 예제
START TRANSACTION;

-- 계좌 이체
UPDATE accounts SET balance = balance - 10000 WHERE account_id = 'A001';
UPDATE accounts SET balance = balance + 10000 WHERE account_id = 'B001';

-- 잔액 확인
SELECT balance FROM accounts WHERE account_id IN ('A001', 'B001');

-- 문제없으면 커밋
COMMIT;

-- 문제 발생 시 롤백
-- ROLLBACK;

4.2 격리 수준 설정

-- 격리 수준 확인
SELECT @@transaction_isolation;

-- 격리 수준 설정
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

4.3 Lock 확인 및 관리

-- MySQL: 현재 Lock 상태 확인
SELECT * FROM performance_schema.data_locks;

-- 대기 중인 Lock 확인
SELECT * FROM performance_schema.data_lock_waits;

-- 명시적 Lock (FOR UPDATE: 전용 Lock)
SELECT * FROM accounts WHERE account_id = 'A001' FOR UPDATE;

-- 공용 Lock
SELECT * FROM accounts WHERE account_id = 'A001' FOR SHARE;

5. 핵심 요약

┌─────────────────────────────────────────────────────────────────────────┐
│                         회복과 병행 제어 요약                            │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│   트랜잭션                                                              │
│   ├── ACID 특성: 원자성, 일관성, 격리성, 지속성                         │
│   ├── 연산: COMMIT, ROLLBACK                                            │
│   └── 상태: 활동 → 부분완료 → 완료 (또는 실패 → 철회)                   │
│                                                                         │
│   회복                                                                  │
│   ├── 장애 유형: 트랜잭션, 시스템, 미디어                               │
│   ├── 회복 연산: redo(재실행), undo(취소)                               │
│   └── 회복 기법: 즉시갱신, 지연갱신, 검사시점, 미디어                   │
│                                                                         │
│   병행 제어                                                             │
│   ├── 문제점: 갱신 분실, 모순성, 연쇄 복귀                              │
│   ├── 스케줄: 직렬, 비직렬, 직렬 가능                                   │
│   ├── 로킹: 공용 Lock(S), 전용 Lock(X)                                  │
│   └── 2PL: 확장 단계(Lock만) → 축소 단계(Unlock만)                      │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘
구분DBMS 기능보장하는 특성
회복 기능로그, 덤프, redo/undo원자성, 지속성
병행 제어로킹, 2PL일관성, 격리성