데이터베이스 설계 | 14. 회복과 병행 제어
1. 트랜잭션(transaction)
-
트랜잭션의 개요
- 데이터베이스에서 논리적인 작업의 단위
- 작업 수행에 필요한 연산(SQL문)들의 모임
- 장애가 발생했을 때 데이터를 복구하는 작업의 단위
- 대규모 데이터베이스를 수천, 수만 명 이상의 사용자들이 동시 접근 → 많은 사용자들이 동시에 데이터베이스의 서로 다른 부분 또는 동일한 부분을 접근하면서 데이터베이스 사용
- 트랜잭션 관리
- 회복(recovery) : 데이터베이스를 갱신하는 도중에 시스템이 고장 나도 데이터베이스의 일관성 유지
- 병행 제어(Concurrency Control) : 다수 사용자가 데이터베이스를 동시에 접근하도록 허용하면서 DB의 일관성 유지
- UPDATE문 사용 : 두 UPDATE문의 순서 중요 X
- 두 개의 UPDATE문은 둘 다 완전하게 수행되거나 한 UPDATE문도 수행되어서는 안되도록 하나의 트랜잭션(단위)처럼 DBMS가 보장해야 함
- 트랜잭션의 특성(ACID) : DBMS가 트랜잭션의 4가지 특성을 보장
- 원자성(Atomicity) : 한 트랜잭션 내의 모든 연산들이 완전히 수행되거나 전혀 수행되지 않음을 의미
- 시스템이 다운되는 경우
- 부분적으로 데이터베이스를 갱신한 트랜잭션의 영향을 취소함으로써 트랜잭션의 원자성 보장
- 완료된 트랜잭션이 갱신한 사항은 트랜잭션의 영향을 재수행함으로써 트랜잭션의 원자성 보장
- DBMS의 회복 모듈이 트랜잭션의 원자성 보장
- 시스템이 다운되는 경우
- 일관성(Consistency) : 어떤 트랜잭션이 수행되기 전에 DB가 일관된 상태를 가졌다면 트랜잭션이 수행된 후에 DB는 또 다른 일관된 상태 가짐
- 일관적 상태의 데이터베이스 → 트랜잭션 수행 → 새로운 일관적 상태의 데이터베이스
- DBMS의 병행 제어 모듈이 트랜잭션의 일관성을 보장
- 고립성(Isolation) : 한 트랜잭션이 데이터를 갱신하는 동안 이 트랜잭션이 완료되기 전에는 갱신중인 데이터를 다른 트랜잭션들이 접근하지 못하도록 해야 함
- 다수의 트랜잭션들이 동시에 수행되더라도 그 결과는 어떤 순서에 따라 트랜잭션들을 하나씩 차례대로 수행한 결과와 같아야 함
- DBMS의 동시성 제어 모듈이 트랜잭션의 고립성을 보장
- 지속성(Durability) : 한 트랜잭션이 성공적으로 완료되면 이 트랜잭션이 갱신한 것은 그 후에 시스템에 고장이 발생하더라도 손실되지 않고 영구적이어야 함
- 완료된 트랜잭션의 효과는 시스템이 고장이 난 경우에도 데이터베이스에 반영되어야 함
- DBMS의 회복 모듈이 트랜잭션의 지속성을 보장
- 원자성(Atomicity) : 한 트랜잭션 내의 모든 연산들이 완전히 수행되거나 전혀 수행되지 않음을 의미
-
트랜잭션의 완료와 철회
- 완료(Commit) : 트랜잭션이 성공적으로 수행되었음을 선언(SQL 구문상 : COMMIT WORK)
-
트랜잭션에서 변경하려는 내용이 데이터베이스에 완전하게 반영
-
철회(Rollback) : 트랜잭션이 수행하는데 실패했음을 선언(SQL 구문상 : ROLLBACK WORK)
- 트랜잭션에서 변경하려는 내용이 데이터베이스에 일부만 반영된 경우 → 원자성을 보장하기 위해서, 트랜잭션이 갱신한 사항을 수행되기 전의 상태로 되돌림
연산 COMMIT ROLLBACK 의미 완료(성공적인 종료) 철회(비성공적인 종료) DBMS의 트랜잭션 관리모듈에게 알리는사항 트랜잭션이 성공적으로 끝났음 데이터베이스는 새로운 일관된 상태를 가짐 트랜잭션이 수행한 갱신을 데이터베이스에 반영해야 함 트랜잭션의 일부를 성공적으로 끝내지못했음 데이터베이스가 불일치 상태를 가질 수 있음 트랜잭션이 수행한 갱신이 데이터베이스에 일부 반영되었다면 취소해야 함 
-
- 완료(Commit) : 트랜잭션이 성공적으로 수행되었음을 선언(SQL 구문상 : COMMIT WORK)
-
트랜잭션의 상태

- 활동 상태 : 트랜잭션이 수행되기 시작하여 현재 수행 중
- 부분 완료 상태 : 트랜잭션의 마지막 연산이 실행된 직후 트랜잭션의 수행 결과를 데이터베이스에 아직 반영하지 X
- 완료 상태 : 트랜잭션이 수행한 결과가 데이터베이스에 반영되어 새로운 일관된 상태가 되면서 트랜잭션이 종료
- 실패 상태 : 장애가 발생하여 트랜잭션의 수행이 중단
- 철회 상태 : 지금까지 실행한 트랜잭션의 연산을 모두 취소하고 트랜잭션이 수행되기 전의 DB 상태를 되돌리면서 트랜잭션 종료
2. 장애와 회복(recovery)
-
장애의 유형
- 트랜잭션 장애 : 트랜잭션 수행 중 오류가 발생되어 정상적으로 수행을 계속할 수 없는 상태
- 트랜잭션의 논리적 오류, 잘못된 데이터 입력, 시스템 자원의 과다 사용 요구, 처리 대상 데이터의 부재 등
- 시스템 장애 : 중앙 처리 장치, 메인 메모리, 전원 공급 장치 등 하드웨어의 결함으로 정상적으로 수행을 계속할 수 없는 상태
- 하드웨어 이상으로 인한 메모리에 저장된 정보가 손실되거나 교착 상태가 발생한 경우 등
- 미디어 장애 : 디스크 헤드, 디스크 컨트롤러 등 디스크 장치의 결함으로 디스크에 저장된 DB의 일부 혹은 전체가 손상된 상태
- 디스크 헤드의 손상이나 고장 등
- 저장 장치의 종류
- 휘발성(volatile) 저장장치(소멸성) : 장애가 발생하면 저장된 데이터가 손실됨 ex) 메인 메모리(DRAM, SRAM) 등
- 비휘발성(nonvolatile) 저장 장치(비소멸성) : 장애가 발생해도 저장된 데이터가 손실되지 X : 단, 디스크 헤더 손상 같은 저장 장치 자체에 이상이 발생하면 데이터 손실될 수 있음 ex) 디스크, 자기 테이프 등
- 안정(stable) 저장 장치 : 비휘발성 저장 장치를 이용해 데이터 복사본 여러 개를 만드는 방법으로, 어떤 장애가 발생해도 데이터가 손실되지 않고 데이터를 영구적으로 저장할 수 있음
- 트랜잭션 장애 : 트랜잭션 수행 중 오류가 발생되어 정상적으로 수행을 계속할 수 없는 상태
-
데이터베이스의 저장 연산

- Input(B) 연산 : 데이터베이스 항목 B를 포함하고 있는 블록을 주기억장치의 버퍼로 읽어들임
- Output(A) 연산 : 데이터베이스 항목A를 포함하고 있는 버퍼 블록을 디스크에 기록함
- Write(A) : 프로그램 변수 A값을 주기억장치 내의 데이터베이스 항목 A에 기록함
- Read(B) 연산 : 주기억장치 버퍼에서 데이터베이스 항목 B의 값을 프로그램 변수 B로 복사
-
회복의 개요
- 회복 : 데이터베이스를 장애 발생 이전의 일관된 상태로 복원시키는 것
- 회복 관리자(Recovery Manager) : DBMS 코드의 10% 이상을 차지, 신뢰성 있는 회복 책임
- 회복의 기본 원리 : 중복(Redundancy)
- 덤프(Dump) : 데이터베이스 전체를 다른 저장장치에 복제(Archive)
- 로그(Log) : 변경 연산이 실행될 때마다 데이터 아이템의 옛 값과 새 값을 별도의 파일에 기록
- 회복을 위한 조치
- Redo : 가장 최근 복제본과 Log를 이용해 복제본이 만들어진 이후에 실행된 모든 변경 연산을 재실행하여 장애가 발생하기 직전의 데이터베이스 상태로 복구
- Undo : Log를 이용해 모든 변경들을 취소해서 원래의 데이터베이스 상태로 복원하는 것(단일 연산에 대해 적용)
- Rollback : 한 트랜잭션에 대해 적용
-
회복의 필요성 : 어떤 트랜잭션 T를 수행하는 도중 시스템이 다운되었을때, T의 수행 효과가 디스크의 데이터베이스에 일부 반영되었을 수 있음 → 어떻게 T의 수행을 취소(Undo)하여 원자성을 보장할 것인가? : 트랜잭션 T가 완료된 직후 시스템 다운되었을때, T의 모든 갱신 효과가 메인 메모리로부터 디스크에 기록되지 않았을 수 있음 → 어떻게 T의 수행 결과가 데이터베이스에 완전하게 반영되도록 재수행(Redo)하여 지속성을 보장할 것인가? : 디스크 헤드 등의 고장으로 디스크의 데이터베이스에 접근할 수 없는 경우 → 미디어 장애가 발생하면 어떻게 할 것인가?
-
데이터베이스 로그(Log)
- 트랜잭션의 원자성과 지속성을 보장하기 위해 DBMS는 데이터베이스의 항목에 영향을 미치는 모든 트랜잭션의 연산들에 대해서 로그라고 부르는 특별한 파일을 유지함
- 로그는 데이터베이스 회복에 필수적이므로 일반적으로 안정 저장 장치(stablestorage)에 저장됨
- 이중 로그(DualLogging) : 로그를 두 개의 디스크에 중복해서 저장
- 각 로그 레코드가 어떤 트랜잭션에 속한 것인가를 식별하기 위해 각 로그 레코드마다 트랜잭션 ID를 포함시킴
- 각 로그 레코드는 로그 순서 번호(LSN : Log Sequence Number)로 식별 됨
- 동일한 트랜잭션에 속하는 로그 레코드들은 연결 리스트로 유지 됨
-
로그 레코드의 유형
- [Trans-ID, start] : 한 트랜잭션이 생성될 때 기록되는 로그 레코드
- [Trans-ID, X, old_value, new_value] : 주어진 Trans_ID를 갖는 트랜잭션이 데이터 항목 X를 이전 값에서 새 값으로 수정했음을 나타내는 로그 레코드
- [Trans-ID, commit] : 주어진 Trans-ID를 갖는 트랜잭션이 데이터베이스에 대한 갱신을 모두 성공적으로 완료함을 나타내는 로그 레코드
- [Trans-ID, abort] : 주어진 Trans_ID를 갖는 트랜잭션이 철회되었음을 나타내는 로그 레코드
-
로그 우선 기록(WAL : Write-Ahead Logging)
- 트랜잭션이 갱신한 데이터 항목을 디스크에 저장된 데이터베이스에 기록하기 전 로그 레코드에 먼저 기록함
- 트랜잭션이 실행 도중 장애가 발생했을 때 데이터베이스에 기록된 변경내용을 취소하려면 로그 레코드에 기록이 있어야 함
- 갱신된 결과가 데이터베이스에 먼저 기록되고 그 사실을 로그 레코드에 기록하기 전 장애가 발생하면? → 로그에 갱신된 기록이 없으므로 데이터베이스 내용을 원래대로 복귀시킬 수 없음
-
회복기법

- 로그를 사용한 즉시 갱신
- 트랜잭션이 데이터베이스를 갱신한 사항이 메인 메모리의 버퍼에 유지되다가 트랜잭션이 완료되기 전이라도 디스크의 데이터베이스에 기록될 수 있음
- 데이터베이스에는 완료된 트랜잭션의 수행 결과뿐만 아니라 철회된 트랜잭션의 수행 결과도 반영될 수 있음
- 데이터 블록이 Output되는 순서는 Write되는 순서와 다를 수 있음
- 복구과정
- 로그 파일이 기록된 마지막부터 반대 방향으로 순차적 검색(로그 아래에서 위로)
- <T,start>가 있으나 <T, commit>가 없으면 Undo연산을 수행하고, <T, start>가 있으나 <T, commit>가 있으면 무시함
- 로그 파일의 처음에 도달했으면 반대 방향으로 순차적 검색(로그 처음부터 아래로)
- <T,start>가 있으나 <T, commit>가 있으면 Redo 연산을 수행하고, <T, start>가 있으나 <T, commit>가 없으면 무시함
- 복구과정
- 로그를 사용한 지연 갱신
- 트랜잭션의 실행이 성공적으로 완료될 때까지 갱신 내용을 디스크에 저장하지 않고 지연시킴 → Undo 연산이 필요 없음/로그 레코드 형식 <Trans-ID, X,new_value> old_value 불필요
- 트랜잭션이 실행되는 동안에는 갱신된 내용이 주기억 장치의 버퍼에 기록
→ 트랜잭션이 완료된 후 적당한 시점에 버퍼의 내용이 디스크로 저장됨
- 복구과정
- 로그 파일의 처음부터 기록을 순차적으로 검색(로그 처음부터 아래로)
- <T,start>가 있으나 <T, commit>가 있으면 Redo 연산을 수행하고, <T, start>가 있으나 <T, commit>가 없으면 무시함
- 복구과정
- 검사 시점(checkpoint)
- 시스템이 다운되기 직전에 완료된 트랜잭션이 갱신한 내용은 메인 메모리의 버퍼에 남아있으면서 아직 디스크에 기록되지 않았을 가능성이 높으므로 트랜잭션의 갱신 사항을 재수행해야 함
- But 시스템이 다운된 시점으로부터 오래 전에 완료된 트랜잭션들이 데이터베이스를 갱신한 사항은 이미 디스크에 반영되었을 가능성이 큼
- DBMS가 로그를 사용하더라도 어떤 트랜잭션의 갱신 사항이 메인 메모리 버퍼로부터 디스크에 기록되었는가를 구분할 수 없음 → 회복 시 재 수행할 트랜잭션의 수를 줄이기 위해서 주기적으로 체크 포인트를 수행함
- 체크 포인트 시점에는 메인 메모리의 버퍼 내용이 디스크에 강제로 기록됨 → 체크 포인트를 수행하면 로그와 데이터베이스의 내용이 일치하게 됨
- 체크 포인트 작업이 끝나면 로그에 [checkpoint] 로그 레코드가 기록됨
- 일반적으로 체크 포인트를 10~20분마다 한 번씩 수행
- 불필요한 회복 작업을 수행하지 않아 회복 시간 단축
- 체크 포인트할 때 수행되는 작업
- 수행 중인 트랜잭션을 일시적으로 중지 시킴
- 메인 메모리의 로그 버퍼를 디스크에 강제로 출력
- 메인 메모리의 데이터베이스 버퍼를 디스크에 강제로 출력
- [checkpoint] 로그 레코드를 로그 버퍼에 기록한 후 디스크에 강제로 출력
- 체크 포인트 시점에 수행 중이던 트랜잭션들의 ID도 [checkpoint] 로그 레코드에 함께 기록
- 일시적으로 중지된 트랜잭션의 수행을 재개
- 미디어 회복
- 데이터베이스가 저장되어 있는 디스크의 헤드 등이 고장 나서 데이터베이스를 읽을 수 없는 경우 → 주기적으로 자기 테이프에 전체 데이터베이스와 로그를 백업하고, 자기 테이프를 별도의 공간에 안전하게 보관
- 전체 데이터베이스를 백업하는 것은 시간이 매우 오래 걸리는 작업 → 최근 백업 이후에 갱신된 내용만 백업을 하는 점진적인 백업(Incremental Backup)이 바람직
- 로그를 사용한 즉시 갱신
3. 병행 제어(concurrency control)
- 병행 제어의 개요
- DBMS의 성능 향상을 위해서 여러 사용자의 질의나 프로그램들을 동시에 수행하는 것이 필수적
- 동시에 수행되는 트랜잭션이 데이터베이스에 미치는 영향과 순차적으로 수행되는 트랜잭션이 데이터베이스에 미치는 영향이 같도록 보장
- 다수 사용자의 데이터베이스 동시 접근을 허용하면서 데이터베이스의 일관성을 유지하고 서로 간섭하지 못하도록 보장
- 병행 수행의 문제
- 병행 제어를 하지 않고 다수의 트랜잭션을 동시 수행할 때 문제점은?
- 갱신 손실(Lost Update) : 수행 중인 트랜잭션이 갱신한 내용을 다른 트랜잭션이 덮어씀으로써 갱신이 무효가 됨
- 연쇄 복귀(Cascading Rollback, 오손 데이터 읽기) : 트랜잭션이 완료되기 전에 장애가 발생하여 Rollback 연산 수행 시 : 트랜잭션이 장애 발생 전 변경한 데이터를 가져와 변경 연산을 실행한 또 다른 트랜잭션에도 Rollback 연산을 연쇄적으로 실행
- 모순성(Inconsistency) : 한 트랜잭션이 여러 개의 데이터 변경연산을 실행할 때 : 일관성 없는 상태의 데이터베이스에서 가져와 연산을 실행함으로써 모순된 결과가 발생하는 것
- 반복할 수 없는 읽기(Unrepeatable Read) : 한 트랜잭션이 동일한 데이터를 반복해서 읽을 때 서로 다른 값을 읽음
- 트랜잭션 스케줄
- 직렬 스케줄(Serial Schedule) : 트랜잭션들을 한 번에 한 트랜잭션씩 차례대로 수행함
- 비 직렬 스케줄(Non-serial Schedule) : 인터리빙 방식을 이용하여 트랜잭션들을 동시에 수행함
- 직렬 가능(Serializable) : 비 직렬 스케줄의 결과가 직렬 스케줄의 수행 결과와 동등하게 되는 것
- 비 직렬 스케줄의 수행으로 생성된 결과는 정확할 수도 잘못될 수도 있음 → DBMS가 직렬 가능 스케줄인지 검사하기보다 직렬 가능성을 보장하는 병행 제어 기법 사용
- 병행 제어 기법
-
로킹(Locking) : 데이터 항목을 로킹하는 개념은 동시에 수행되는 트랜잭션들의 동시성을 제어하기 위해서 널리 사용되는 기법
-
일반적으로 데이터베이스 내의 모든 데이터 항목마다 로크가 존재함
-
각 트랜잭션이 수행을 시작하여 데이터 항목을 접근할 때마다 요청한 로크에 관한 정보는 로크 테이블에 유지됨
-
트랜잭션이 데이터 항목에 대한 접근을 끝낸 후에 로크를 해제(Unlock)함
-
DBMS는 각 트랜잭션의 연산 별로 적당한 수준의 로크를 자동으로 설정함
-
DBMS마다 로크 구현 방식과 세부 메커니즘이 다름
-
독점 로크(X-lock, eXclusive lock) : 갱신을 목적으로 데이터 항목에 접근할 때 요청
-
공유 로크(S-lock, Shared lock) : 읽기를 목적으로 데이터 항목에 접근할 때 요청
-
로크 양립성 행렬

공유 로크와 독점 로크가 동시에 걸릴 수 없음
-
2단계 로킹 프로토콜(2-phase Locking Protocol)
- 로크를 요청하는 확장 단계와 로크를 해제하는 수축 단계인 2단계로 이뤄짐
- 로크 확장 단계가 지난 후에 로크 수축 단계에 들어감
- 일단 로크 한 개라도 해제하면 로크 수축 단계에 들어감
- 로크 확장 단계(1단계) : 트랜잭션이 데이터 항목에 대해 새 로크를 요청할 수 있지만 보유하고 있던 로크를 하나라도 해제할 수 X
- 로크 수축 단계(2단계) : 보유하고 있던 로크를 해제할 수 있지만 새로운 로크를 요청할 수 X : 로크를 조금씩 해제할 수도 있고, 트랜잭션이 완료 시점에 이르렀을 때 한꺼번에 모든 로크해제 가능 → 일반적으로는 한꺼번에 해제하는 방식 사용
-
로크 포인트(Lock Point) : 한 트랜잭션에 필요로 하는 모든 로크를 걸어놓은 시점
로크를 조금씩 해제

로크를 한꺼번에 해제

-
교착상태(Deadlock) : 두 개 이상의 트랜잭션들이 서로 상대방이 보유하고 있는 로크를 요청하면서 기다리는 상태

- T1이 X에 대해 독점 로크를 요청하여 허가 받음
- T2가 Y에 대해 독점 로크를 요청하여 허가 받음
- T1이 Y에 대해 공유 로크나 독점 로크를 요청하면 로크가 해제될 때까지 기다리게 됨
- T2가 X에 대해 공유 로크나 독점 로크를 요청하면 로크가 해제될 때까지 기다리게 됨
- 2단계 로킹 프로토콜에서는 트랜잭션의 직렬 가능성을 보장할 수 있지만 교착 상태가 발생할 수 있음
- 해결 방법 : 교착 상태 방지 기법(교착 상태를 탐지하고 희생자를 선정하여 교착 상태를 푸는 기법) → 수행할 사항이 많이 남은 트랜잭션을 희생자로 선택
-
다중 로크 단위(Multiple Lock Granularity)
- 대부분의 트랜잭션이 소수의 투플을 접근하는 데이터베이스 응용에서는 투플 단위로 로크를 해도 로크 테이블을 다루는 시간이 오래 걸리지 않음
- 많은 투플을 접근하는 데이터베이스 응용에서 투플 단위로만 로크를 한다면? → 로크 테이블에서 로크 충돌을 검사하고, 로크 정보를 기록하는 시간이 오래 걸림
- 트랜잭션이 접근하는 투플의 수에 따라 로크를 하는 데이터 항목의 단위 구분이 필요
- 다중 로크 단위 : 데이터베이스 → 릴레이션 → 디스크 블록 → 투플
- 일반적으로 DBMS는 각 트랜잭션에서 접근하는 투플 수에 따라 자동적으로 로크 단위 조정
- 데이터베이스 : 로크 단위가 작을수록 로크의 수는 증가
- 릴레이션 : 로크 단위가 작을수록 동시성의 정도는 증가
- 디스크 블록(페이지) : 로크 단위가 작을수록 구현의 용이성은 복잡
- 레코드(투플) : 로크 단위가 작을수록 병행 제어 기법의 용이성은 복잡
-
- 병행 제어를 하지 않고 다수의 트랜잭션을 동시 수행할 때 문제점은?