-
DB - 트랜잭션 관리Database 2022. 4. 23. 19:09
데이터베이스는 보통 비휘발성 저장 장치인 디스크에 데이터를 저장하며,전체 데이터베이스의 일부분을 메인 메모리에 유지한다.
DBMS는 데이터를 고정 길이의 페이지(page)로 저장하며, 디스크에서 읽거나 쓸 때에 페이지 단위로 입출력이 이루어진다.
메인 메모리에 유지하는 페이지들을 관리하는 모듈을 보통 페이지 버퍼(page buffer) 관리자 또는 버퍼 관리자라고 부르는데, DBMS의 많은 주요 모듈 중에서 매우 중요한 모듈 중의 하나이다.
DBMS는 각 제품마다 구조가 다르기는 하지만, 위 그림과 같이 크게 질의 처리기(Query Processor)와 저장 시스템(Storage System)으로 나눠볼 수 있다. MySQL의 경우에는 InnoDB, MyISAM 등과 같이 여러 하부 저장 시스템을 선택할 수 있는데, 이와 같은 모델은 상부의 질의 처리기와 하부의 저장 시스템 간의 명확하게 구분되는 계층(layered) 구조에 해당한다.
버퍼 관리 정책은 트랜잭션 관리에 매우 중요한 결정을 가진다.
Undo???
오퍼레이션 수행 중에 수정된 페이지들이 버퍼 관리자의 버퍼 교체 알고리즘에 따라서 디스크에 write 되는 경우가 있다. 버퍼 교체는 전적으로 버퍼의 상태에 따라서 결정되며, 일관성 관점에서 봤을 때는 임의의 방식으로 일어나게 된다. 즉 아직 완료되지 않은 트랜잭션이 수정한 페이지들도 디스크에 출력될 수 있으므로, 만약 해당 트랜잭션이 어떤 이유든 정상적으로 종료될 수 없게 되면 트랜잭션이 변경한 페이지들은 원상 복구되어야 한다. 이러한 복구를 UNDO라고 한다.
만약 버퍼 관리자가 트랜잭션 종료 전에는 어떤 경우에도 수정된 페이지들을 디스크에 쓰지 않는다면, UNDO 오퍼레이션은 메모리 버퍼에 대해서만 이루어지면 되는 식으로 매우 간단해질 수 있다. 하지만 이 정책은 매우 큰 크기의 메모리 버퍼가 필요하다는 문제점을 가지고 있다.
수정된 페이지를 디스크에 쓰는 시점을 기준으로 다음과 같은 두 개의 정책으로 나누어 볼 수 있다.
- steal : 수정된 페이지를 언제든지 디스크에 쓸 수 있음
- 수정된 페이지가 어떤 시점에도 디스크에 써질 수 있기 때문에 필연적으로 undo 로깅과 복구를 수반함
- 거의 모든 DBMS가 채택하는 버퍼 관리 정책
- 장점 - 필요에 따라 commit 되지 않은 buffer들을 disk로 내보내고 빈buffer로 만드는것이 가능 (메모리 활용 유연)
- no-steal : 수정된 페이지들을 최소한 트랜잭션 종료 시점까지는 버퍼에 유지함
Redo???
커밋한 트랜잭션의 수정은 어떤 경우에도 유지(durability)되어야 한다.
이미 커밋한 트랜잭션의 수정을 재반영하는 복구 작업을 REDO 복구라고 하는데, REDO 복구 역시 UNDO 복구와 마찬가지로 버퍼 관리 정책에 영향을 받는다.
트랜잭션이 종료되는 시점에 해당 트랜잭션이 수정한 페이지들을 디스크에도 쓸 것인가 여부로 두 가지 정책이 구분된다.
- FORCE : 수정했던 모든 페이지를 트랜잭션 커밋 시점에 디스크에 반영함
- NO-FORCE : 수정했던 페이지를 트랜잭션 커밋 시점에 디스크에 반영하지 않음
- 거의 모든 DBMS가 채택하는 정책
- 장점 - commit된 후에 바로 block을 없애지 않으면 다른 T가 그 block이 필요할때 다시 읽어들이는 과정이 생략 (I/O cost save)
FORCE 정책을 따르면 트랜잭션이 커밋되면 수정되었던 페이지들이 이미 디스크 상의 데이터베이스에 반영되었으므로 REDO 복구가 필요 없게 된다. 반면에 NO-FORCE 정책을 따른다면 커밋한 트랜잭션의 내용이 디스크 상의 데이터베이스 상에 반영되어 있지 않을 수 있기 때문에 반드시 REDO 복구가 필요하게 된다.
사실 FORCE 정책을 따르더라도 데이터베이스 백업으로부터의 복구인 미디어(media) 복구 시에는 REDO 복구가 요구된다.
트랜잭션관리
UNDO 복구와 REDO 복구를 위해서 가장 널리 쓰이는 구조는 로그(log)이다.
로그(log)
로그는 로그 레코드의 연속이며 데이터베이스의 모든 갱신 작업을 기록한다.
로그는 이론적으로는 안정적 저장 매체(stable storage)에 기록된다고 하는데, 안정적 저장 매체는 어떤 경우에도 절대로 손실이 발생하지 않는 실존하기 힘든 이상적인 매체이다. RAID 등 인프라 시스템의 도움 외에도 DBMS 자체적으로 여러 벌의 로그를 유지하는 등 안정적 저장 매체처럼 동작하게 하는 기법을 사용하기도 한다. 하지만 대부분 DBMS는 성능 상의 이유로 하나의 로그를 유지한다.
로그는 덧붙이는(append) 방식으로 기록되며, 각 로그 레코드는 고유의 식별자를 가진다. 로그 레코드의 식별자를 LSN(Log Sequence Number) 혹은 LSA(Log Sequence Address)라고 부른다.
로그는 항상 뒤에 덧붙이는 방식으로 쓰이기 때문에, 로그 식별자는 단조 증가하는 성질을 가진다.
로그 데이터는 기록할 오브젝트의 타입에 따라서 물리적/논리적 로깅으로 분류할 수 있고, 데이터베이스의 상태 또는 변화를 야기한 전이(transition)를 기록하느냐에 따라서 분류할 수 있다.
물리적인 상태 로깅(physical state logging)
- DBMS에서 가장 널리 쓰이는 기본적인 로깅 방법
- 갱신 이전 이미지와 이후 이미지를 모두 다 가지고 있으며, UNDO 복구 때에는 이전 이미지로 현재 이미지를 대체하며, REDO 복구 때에는 이후 이미지를 반영하는 방식으로 복구가 이루어짐
- 결국 이전 이미지 혹은 이후 이미지로 단순히 대체하는 작업
- 예를 들어,
- UPDATE 문장에 대한 로깅은 수정 이전 이미지(즉, 수정 전 레코드 이미지)와 이후 이미지(새로 갱신하는 레코드 이미지)를 모두 기록하고, UNDO 시에는 수정 이전 이미지로 대체하는 식
- REDO가 필요한 경우에는 수정 이후 이미지를 반영하는 식
- 물리적 상태 로깅은 때로는 페이지 수준(예를 들어, 인덱스나 데이터 파일의 헤더 페이지의 변경 로깅)에서 이루어지기도 하고, 레코드 수준에서 이루어지기도 함
물리적인 전이 로깅(physical transition logging)
- 페이지 혹은 레코드에 대해서 이전 및 이후 이미지를 모두 기록하기 보다는 XOR 차이점을 기록하는 방식
- 복구 시점에서 로그 레코드에 기록된 XOR 이미지와 레코드 이미지를 이용하여 UNDO 복구와 REDO 복구를 수행
논리적인 전이 로깅(logical transition logging)
- 오퍼레이션 로깅(operation logging)이라고도 함
- 물리적인 로깅이 결과 값을 기록하는 방식이라면 논리적인 로깅은 어떤 일을 했었는가를 기록하는 방식
- 예를 들어,
- a = a + 1과 같은 연산을 로깅할 때 이전 값 0, 이후 값 1을 물리적으로 기록할 수도 있고, a = a + 1 이라는 연산 그 자체를 기록 가능.
- 논리적인 로그에 대한 복구 작업은 REDO를 위하여 로그 레코드에 기록된 오퍼레이션을 재수행하거나, UNDO를 위하여 역 오퍼레이션을 수행하는 방식으로 이루어진다.
- 로그 레코드의 크기를 크게 줄여준다는 장점
- 물리적으로 복구하기 쉽지 않은 자료 구조에 대한 로깅을 쉽게 해줌
- 예를 들어, 인덱스 구조로 많이 사용되는 B+-tree 또는 B-tree 는 split, merge 와 같은 SMO(Structure Modification Operation)를 통해서 레코드의 위치가 계속 변경됨
- 따라서 로깅 시점과 복구 시점의 데이터 물리적 위치가 같다는 점이 보장되지 않기 때문에(페이지 내의 위치가 다를 수도 있고, 심지어 다른 페이지에 위치할 수도 있다), 물리적인 로그를 통해서 복구하기가 쉽지 않지만, 논리적인 로그를 통해서 보다 쉽게 복구할 수 있음.
- 즉, 인덱스에 키 값 k와 포인터 p가 저장되었다는 논리 로그에 대한 REDO 복구는 인덱스에 (k, p)를 다시 삽입하는 작업이면 충분하고, UNDO 복구는 (k, p)를 인덱스에서 제거하는 작업을 수행하면 된다.
DBMS 제품들은 위 물리적인 상태 로깅, 물리적인 전이 로깅, 논리적인 전이 로깅 방법 중에 하나만을 선택하여 사용하는 것이 아니라 이들을 적절하게 혼용한다.
로그가 쓰여지는 방식
로그는 로그 타입에 관계없이 다음의 규칙에 따라 써진다.
- 해당 업데이트가 데이터베이스에 써지기 전에 먼저 관련된 UNDO 정보가 로그에 써져야 한다.
- 이 원칙을 WAL(Write Ahead Logging)이라고 부름. 어떤 경우에도 UNDO 복구가 되기 위해서는 반드시 WAL 규칙이 준수되어야 함.
- 트랜잭션이 정상적으로 종료 처리되기 위해서는 먼저 REDO 정보가 로그에 써져야 한다. 역시 어떤 경우에도 REDO 복구를 할 수 있기 위해서는 REDO 로그가 적어도 커밋 시점에는 써져야 한다.
Write Ahead Logging(WAL)
- 모든 수정은 적용하기 전에 먼저 로그에 기록함
- 트랜잭션 발생시 로그에 일단 작성하여 기록을 남기고, 데이터가 쌓이면 이를 disk에 data block 형태로 flush 함
- 도중에 트랜잭션이 fail되어도 현재까지 이뤄진 작업과 앞으로 해야할 작업을 로그로 분석하여 다시 진행 가능
DBMS는 로그 레코드를 위한 별도의 버퍼를 유지하는데, 이를 로그 버퍼라고 한다.
로그 버퍼 관리는 DBMS마다 서로 다른 방식으로 구현하지만 로그 버퍼를 통해서 로그 파일에 입출력한다는 점은 같다. 성능을 위해서 로그 버퍼에 로그 레코드를 모았다가 블록 단위로 로그 파일에 출력한다.
트랜잭션들이 동시에 수행을 하면서 각각의 연산에 대해서 로그 레코드를 생성하게 되는데, 이들은 로그 버퍼에 유지되게 되고 몇몇 시점에 로그 파일에 써지게 된다.
로그 버퍼에 유지된 로그 레코드는
- 어떤 트랜잭션이 커밋을 요청한 경우
- WAL을 해야 하는 경우
- 로그 버퍼가 다 소진된 경우
- DBMS가 내부적으로 필요로 하는 경우(예를 들어, 체크 포인트(checkpoint) 연산, 로그 관리 연산 등
위 경우에 로그 파일에 출력된다.
로그 버퍼는 상대적으로 작기 때문에 긴 트랜잭션이 수행 중인 경우에는 로그 버퍼가 소진될 수 있다.
어떤 트랜잭션이 커밋을 요청하는 경우에는 해당 트랜잭션의 마지막 로그 레코드까지 출력하면 된다.
로그로 어떻게 복구???
복구에는 두 가지 종류로,
- 사용자의 요청 또는 오류 발생 등으로 인해서 시스템이 트랜잭션을 철회하는 경우
- 소프트웨어 문제나 하드웨어 문제 등으로 인해서 장애가 발생하고 데이터베이스 시스템이 재시작 복구(restart recovery)하는 경우
트랜잭션 철회??
트랜잭션을 철회하는 경우는 시스템은 정상적으로 동작하고 있는 중이며 특정 트랜잭션만 철회하는 경우이다.
- 먼저 로그를 역방향으로 탐색하면서 해당 트랜잭션의 UNDO 복구가 필요한 로그를 찾아서 이에 해당하는 UNDO 연산을 수행
- 역방향으로 로그를 탐색하면서 트랜잭션 수행 순서의 역순으로 UNDO를 수행해야 정확하게 UNDO가 이루어질 수 있다.
- UNDO를 수행하고 나면 해당 UNDO 작업에 대한 보상 로그 레코드(CLR, Compensation Log Record)라고 하는 REDO 전용 로그를 쓰게 되는데, UNDO를 하고 난 이후에 다시 UNDO를 해서 복구가 잘못 이루어지지 않도록 하기 위함
- CLR은 이전 로그 레코드 위치를 UNDO 로그의 이전 로그를 가리키도록 하여 이후에는 한 번 UNDO된 로그를 다시 접근하여 재차 UNDO하게 되는 일이 발생되지 않도록 해줌.
- 이전 로그를 계속 탐색하면서 해당 트랜잭션의 시작 로그까지 도달하면 해당 트랜잭션의 철회 복구가 완료된 것
재시작 복구??
장애 발생 이후 데이터베이스가 재시작 복구하는 경우에는 크게 3 단계로 복구가 이루어진다.
- 로그 분석 단계,
- 마지막 체크포인트(checkpoint) 시점부터 최근 로그(EOL, End of Log)까지 로그를 탐색하면서 어디서부터 시스템이 복구를 시작해야 하는지, 어느 트랜잭션들을 복구해야 하는지 등등을 알아내는 단계
- REDO 복구 단계,
- 복구를 시작해야 하는 시점부터 장애 발생 직전 시점까지 REDO가 필요한 모든 로그를 REDO 복구를 하는 단계.
- 이 단계에서는 심지어 실패한 트랜잭션의 REDO 로그조차도 REDO를 하게 됨
- 이렇게 하면 이후의 복구 단계를 매우 간단하게 하는 효과를 가져다 줌.
- 이 단계에서는 모든 트랜잭션에 대해서 REDO 복구만 한다는 점이 중요
- 이러한 REDO 복구가 완료된 시점의 데이터베이스 상태는 장애 발생 시점의 상태와 같게 됨.
- UNDO 복구 단계
- 로그를 최신 시점부터 다시 역방향으로 탐색하면서 UNDO 복구가 필요한 로그들에 대해서 UNDO 복구를 수행.
- 여기서 수행하는 UNDO는 결국 위에서 설명한 트랜잭션 철회 시에 수행하는 UNDO와 같은 방식
- repeating history를 통해 데이터베이스 상태를 장애 시점까지 복원해두고 UNDO 복구를 여러 트랜잭션의 철회로 해결할 수 있음.
- 한 트랜잭션만 철회시키는 것이 아니라 여러 트랜잭션을 철회시킨다는 차이점만 존재.
참고 및 출처 :
'Database' 카테고리의 다른 글
DB - 동시성 제어와 lock (0) 2022.04.17 - steal : 수정된 페이지를 언제든지 디스크에 쓸 수 있음