트랜잭션, 동시성 제어와 회복
ACID와 격리수준, 락·2PL·교착상태, MVCC, WAL·Undo·Redo·체크포인트를 연결해 이해한다.
1. 트랜잭션과 ACID
트랜잭션은 하나의 논리적 작업을 구성하는 데이터베이스 연산의 집합이다. 계좌이체는 출금과 입금이 함께 성공하거나 함께 취소되어야 한다.
START TRANSACTION;
UPDATE account
SET balance = balance - 100000
WHERE account_no = 'A';
UPDATE account
SET balance = balance + 100000
WHERE account_no = 'B';
COMMIT;
| 특성 | 의미 |
|---|---|
| 원자성 Atomicity | 전체가 수행되거나 모두 취소된다. |
| 일관성 Consistency | 트랜잭션 전후에 정의된 무결성 규칙을 만족한다. |
| 격리성 Isolation | 동시 트랜잭션이 서로의 중간 결과를 부적절하게 보지 않도록 한다. |
| 지속성 Durability | 커밋된 결과는 장애가 발생해도 보존된다. |
트랜잭션은 활성 상태에서 연산을 수행하고, 마지막 연산 후 부분 완료 상태를 거쳐 커밋될 수 있다. 오류가 발생하면 실패 후 철회 상태로 이동해 변경을 취소한다.
2. 동시 실행의 문제
갱신 분실
초기 잔액 = 100
T1 T2
read balance = 100
read balance = 100
balance = 100 + 20
balance = 100 - 30
write 120
write 70
최종 70: T1의 +20 결과가 사라짐
주요 이상 현상
| 현상 | 설명 |
|---|---|
| Dirty Read | 다른 트랜잭션이 아직 커밋하지 않은 값을 읽음 |
| Non-repeatable Read | 같은 행을 다시 읽었을 때 다른 값이 보임 |
| Phantom Read | 같은 조건을 다시 조회했을 때 행 집합이 달라짐 |
| Lost Update | 한 트랜잭션의 갱신 결과를 다른 갱신이 덮어씀 |
| Cascading Rollback | 미커밋 값을 읽은 트랜잭션까지 연쇄적으로 취소해야 함 |
3. 격리수준
SQL 표준의 전형적인 관계를 정리하면 다음과 같다. 실제 DBMS는 MVCC 구현 등에 따라 세부 동작이 다를 수 있다.
| 격리수준 | Dirty Read | Non-repeatable Read | Phantom Read |
|---|---|---|---|
| READ UNCOMMITTED | 가능 | 가능 | 가능 |
| READ COMMITTED | 방지 | 가능 | 가능 |
| REPEATABLE READ | 방지 | 방지 | 표준상 가능 |
| SERIALIZABLE | 방지 | 방지 | 방지 |
격리수준이 높을수록 일관성은 강해지지만 잠금 대기·충돌·재시도 비용이 증가할 수 있다.
4. 락과 2단계 로킹
- 공유락 S: 읽기를 위한 락. 여러 트랜잭션이 동시에 공유락을 가질 수 있다.
- 배타락 X: 쓰기를 위한 락. 다른 공유락·배타락과 충돌한다.
| 요청\보유 | S | X |
|---|---|---|
| S | 호환 | 비호환 |
| X | 비호환 | 비호환 |
2단계 로킹(2PL)은 락을 얻는 성장 단계와 락을 해제하는 축소 단계를 분리해 충돌 직렬가능성을 보장한다.
성장 단계: Lock 획득 가능, Unlock 불가
│ 첫 Unlock
▼
축소 단계: Lock 획득 불가, Unlock 가능
Strict 2PL은 배타락을 커밋 또는 롤백까지 유지해 연쇄 복귀를 줄인다.
5. 교착상태
T1: row A의 X락 보유 ── row B의 X락 대기
▲ │
│ ▼
T2: row A의 X락 대기 ── row B의 X락 보유
서로가 가진 자원을 기다리는 순환이 생기면 교착상태이다. DBMS는 대기 그래프 탐지, 타임아웃, 희생 트랜잭션 롤백 등으로 해결한다. 응용 프로그램은 여러 자원을 같은 순서로 접근하고 트랜잭션을 짧게 유지해 발생 가능성을 줄일 수 있다.
6. MVCC
다중 버전 동시성 제어(MVCC)는 데이터의 여러 버전을 관리해 읽기와 쓰기의 충돌을 줄인다.
과거 커밋 버전 ──► 현재 커밋 버전 ──► 미커밋 새 버전
▲
└─ 조회 시작 시점에 맞는 버전을 읽음
일반적으로 읽기는 일관된 스냅샷을 보고, 쓰기 충돌은 별도로 검사한다. MVCC가 모든 이상 현상을 자동으로 제거하는 것은 아니며 격리수준과 DBMS 구현을 함께 봐야 한다.
7. 로그 기반 회복
지속성과 원자성을 보장하려면 변경 내용을 로그에 기록한다.
- WAL(Write-Ahead Logging): 변경된 데이터 페이지를 디스크에 쓰기 전에 관련 로그를 먼저 안정 저장한다.
- Undo: 커밋되지 않은 트랜잭션의 변경을 이전 값으로 되돌린다.
- Redo: 커밋되었지만 데이터 파일에 반영되지 않은 변경을 다시 적용한다.
- 체크포인트: 회복을 시작할 기준점을 만들어 재처리할 로그 범위를 줄인다.
트랜잭션 변경
↓
로그 레코드 생성
↓ WAL: 로그 먼저 저장
로그 디스크 기록
↓
데이터 페이지 기록
↓
장애 발생
├─ 미커밋 변경: UNDO
└─ 커밋됐지만 미반영: REDO
즉시 갱신 방식에서는 Undo와 Redo가 모두 필요할 수 있다. 세부 로그 구조는 DBMS마다 다르므로 WAL·Undo·Redo·체크포인트의 역할을 구분해야 한다.
8. 우선 그래프로 직렬가능성 판정
서로 다른 트랜잭션이 같은 항목을 접근하고 하나 이상이 쓰기면 충돌한다.
r1(X), w2(X), r2(Y), w3(Y), r3(Z), w1(Z)
X: T1→T2
Y: T2→T3
Z: T3→T1
그래프에 사이클이 있으므로 충돌 직렬가능하지 않다.
9. 회복가능·Cascadeless·Strict
| 성질 | 핵심 조건 |
|---|---|
| Recoverable | T2가 T1 값을 읽었다면 T1 커밋 뒤 T2 커밋 |
| Cascadeless | 커밋된 값만 읽음 |
| Strict | 한 트랜잭션이 쓴 항목을 종료 전 다른 트랜잭션이 읽거나 쓰지 못함 |
Strict 스케줄은 dirty read와 dirty write를 막아 회복을 단순화한다.
10. 다중 단위 잠금과 Write Skew
테이블에 IX가 있다는 것은 하위 행에 X 잠금이 있거나 설정될 수 있음을 뜻한다. 따라서 테이블 전체 S 요청과 충돌할 수 있다.
의사 A: B가 당직임을 읽고 A를 off
의사 B: A가 당직임을 읽고 B를 off
각자 다른 행을 써도 '최소 한 명 당직' 불변식 위반
이는 스냅샷 격리의 write skew다. 직렬가능 격리, 명시적 범위 잠금, 충돌하는 제약 모델 등으로 한 트랜잭션이 재시도되게 해야 한다.
11. STEAL/NO-FORCE와 회복
STEAL → 미커밋 페이지가 디스크에 기록될 수 있음 → UNDO 필요
NO-FORCE → 커밋 페이지가 아직 디스크에 없을 수 있음 → REDO 필요
WAL은 변경 페이지보다 로그를 먼저 안정 저장한다. 체크포인트는 장애를 없애는 기능이 아니라 분석·redo해야 할 로그 범위를 줄이는 기준점이다.
확인 문제
- 우선 그래프에 사이클이 있으면?
- Recoverable 스케줄의 커밋 순서는?
- S-S와 S-X 잠금 호환성은?
- STEAL/NO-FORCE에서 필요한 회복은?
- write skew의 대응은?