- Published on
데이터베이스 트랜잭션과 Undo와 Redo Log
- Authors
- Name
- 트랜잭션이란?
- Name
- 트랜잭션의 ACID
- Name
- Undo Log와 Redo Log
- Name
- Undo Log
- Name
- Redo Log
- Name
- Log가 무엇인데?
- Name
- Log는 언제 쓸까?
Tags
Previous Article
Next Article
트랜잭션이란?
컴퓨터과학에서 트랜잭션이란 **"더이상 분해할 수 없는 작업의 단위"**라고 생각할 수 있다.
즉, 트랜잭션이란 작업의 상태가 작업 "전"과 "후"만 존재한다고 볼 수 있다.
왜 이런 개념이 등장했을까? 기술적, 물리적으론 일련의 여러 작업이 결합된 어떤 작업이
논리적으론 반드시 하나의 작업인 경우를 처리하기 위함이다.
좀 더 구체적으로는 항상 등장하는 예시로 은행 업무를 들 수 있다.
예컨데 A가 B에게 금액 1만원을 송금한다고 가정해보는 것이다.
그렇다면 컴퓨터의 관점에선 A의 계좌 잔액에는 -10,000 연산을 처리하고,
B의 계좌 잔액에 +10,000 연산을 처리해야 한다.
따라서 적어도 2개 이상의 작업이 구성되는 것이다.
그런데 만약 중간에 시스템 장애로 계좌 송금이 중단된다면??
B의 계좌 잔액에 10,000원이 추가된 상태로 작업이 중단되거나,
A의 계좌 잔액에 10,000원이 빠진 상태로 중단되거나..
무언가 심각한 문제가 될 것임이 분명하다.
현실세계의 관점에서는 계좌송금이 반드시 Atomic한 연산이어야 하지만,
기술적으론 그렇지 않을 수 있는 것이다.
따라서 이러한 논리적으로 쪼개질 수 없는 작업을 기술적으로도 그러하게 만들기 위해
등장하는 개념이 우리가 공부할 트랜잭션이다.
트랜잭션의 ACID
트랜잭션의 ACID란 트랜잭션의 작업에 있어 지켜져야 하는 성질들의 앞 글자를 딴 것인데,
구체적으로 다음의 4가지이다.
성질 | 설명 |
---|---|
Atomicity(원자성) | Atomicity는 트랜잭션이 말 그대로 하나의 작업으로서 분해되지 않고 이루어져야 한다는 의미이다. 앞서 얘기했듯 트랜잭션의 부분작업들이 실행되다가 중단되어서는 안된다. 트랜잭션이 실행되면 작업이 성공했거나(모든 작업이 완료) 실패했거나(모든 작업이 취소) 둘 중 하나의 결과만이 존재한다. |
Consistency(일관성) | Consistency는 트랜잭션의 처리 전과 후에 시스템 전체의 일관성이 지켜져야 한다는 의미로, 명시적인 무결성 제약조건을 포함해서 비명시적인 일관성(예를 들어 은행 송금 전과 후에 전체 잔액이 동일해야 한다.)이 지켜져야 한다는 의미이다. |
Isolation(독립성) | Isolation은 동시에 여러 트랜잭션들이 실행되더라도 서로 영향을 주고 받으면 안된다는 의미이다. 이는 트랜잭션의 중간단계의 결과가 다른 트랜잭션에 영향을 주어서는 안된다는 것으로 어찌보면 원자성과 비슷한 맥락에서 이해할 수 있을 것이다. 트랜잭션은 실패와 성공 밖에 없다. |
Durability(지속성) | Durability는 트랜잭션이 성공했을 때 그 변경사항이 영구적으로 시스템에 반영되어야 한다는 것이다. 당연한듯 보이지만, 반대로 생각했을 때 모든 변경사항이 영구적으로 반영될 준비가 되지 않으면 트랜잭션이 완료되었다고 보면 안된다는 관점이 좀 더 다가온다. |
Undo Log와 Redo Log
데이터베이스가 트랜잭션을 보장하기 위해선 어떻게 해야할까?
이를 위해선 트랜잭션 작업이 수행되는 시나리오를 생각해보아야 할 것이다.
트랜잭션이 일단 실행되면 그 결과는 성공과 실패 둘 중 하나라고 말했다.
당연히 둘 중 좀 더 곤란한 경우는 트랜잭션이 실패했을 경우이다.
트랜잭션이 실패했다면, 그 시점까지 진행된 모든 부분작업의 결과들이 취소되고
데이터베이스 전체의 상태가 원상복귀되어야 한다.
Undo Log는 이러한 실패작업의 원상복귀를 위해 미리 복원해놓은 데이터를 말한다.
Undo Log
Undo 작업은 트랜잭션이 중단되었을 때 변경사항을 취소하고 시스템을 원상복구하는 것으로
트랜잭션의 Atomicity와 Consistency와 밀접한 관련이 있다.
Undo Log는 실패한 트랜잭션의 변경사항을 원상복귀하기 위한 데이터이다.
데이터베이스의 모든 작업은 먼저 버퍼에서 이루어지고
디스크에 flush되는데 이러한 flush는 임의의 시점에 일어난다고 보는 것이 편하다.
즉, 트랜잭션이 완료되지 않더라도 디스크에 변경사항이 먼저 출력될 수 있다는 것이다.
이는 수정된 페이지를 언제 디스크에 쓰는지에 관한 두 가지 전략에 따른 것인데,
다음의 두 가지 전략이 있다.
전략 | 설명 |
---|---|
STEAL | 수정된 페이지를 언제든지 디스크에 쓸 수 있다. |
NO-STEAL | 수정된 페이지를 적어도 트랜잭션이 완료되기 전까진 디스크에 반영하지 않는다. |
NO-STEAL 전략은 트랜잭션이 완료되기 전까지 모든 작업을 메모리에 유지시킨다는 것으로
만약 트랜잭션이 중단될 경우 관련된 복구작업을 메모리 안에서만 수행하면 된다.
하지만 실제로는 대부분 DMBS가 STEAL 전략을 사용하는데 이는 한정된 메모리 버퍼를 효율적으로
사용하기 위함이다.
STEAL 전략을 사용하기 때문에 트랜잭션이 중단될 경우 이미 선반영된 변경사항들을 취소하고
원본으로 복구해야 하는데, 이러한 원본사항을 저장하기 위해 Undo Logging이 사용된다.
Redo Log
Redo는 트랜잭션이 완료(Commit)되었을 때 모든 변경사항이 디스크에 반영되는 것을 보장하는 작업으로서
트랜잭션의 Durability와 밀접하게 관련되어있다.
Commit이 일어난 트랜잭션의 변경사항은 모두 디스크에 반영되어있을까?
이를 위해선 다시 트랜잭션이 완료된 시점에 버퍼를 어떻게 관리할 것인지 전략을 살펴보아야 한다.
전략 | 설명 |
---|---|
FORCE | 수정된 페이지를 트랜잭션 커밋 시점에 디스크에 모두 반영되어야 한다. |
NO-FORCE | 수정된 페이지가 커밋 시점에 디스크에 반영되지 않을 수 있다. |
FORCE 전략은 이미 모든 수정사항이 반영되었으니 Redo작업이 필요 없다.
NO-FORCE 전략의 경우 아직 반영되지 않은 페이지가 완전히 반영될 수 있도록 보장(Redo)해야 하는데,
이러한 작업을 위해 Redo Logging을 하게 된다.
더 직관적인 전략은 FORCE인데 이번에도 실제로 DBMS에서 보통 채택하는 것은 NO-FORCE이다.
이유는 트랜잭션의 효율성을 위함인데, 후술하겠지만 Redo Log는 디스크에 연속적인 자료구조로 저장되기 때문에
비교적으로 빠른 쓰기 속도가 보장되고 이는 트랜잭션을 좀 더 빨리 끝낼 수 있다는 장점이 있다.
Log가 무엇인데?
앞서 Redo와 Undo를 얘기하며 계속해서 Redo Log와 Undo Log에 대해서 언급했다.
코딩을 하며 어떤 결과를 출력하기 위해 log는 자주 사용했지만 여기서 얘기하는 log는 무엇일까?
Log란 데이터베이스의 모든 갱신 작업을 기록하기 위한 연속적인 레코드로 보통 디스크에
로그를 위한 공간(파일)을 따로 두어 저장된다.
Log에 저장되는 데이터는 어떤 갱신을 수행했는지에 대한 정보인데,
이는 다시 상태를 저장하는가? 변화를 저장하는가?에 따라 분류된다.
State Logging과 Transition Logging
State Logging은 말그대로 DBMS의 상태를 저장한다는 의미로 갱신작업이 일어나기 전과 후의
데이터를 저장하는 방식이다.
Transition Logging은 데이터의 상태가 아니라 어떤 변화(Operation)를 수행했는지를 저장하는 것으로
예를 들어 a = 0일 때, a = a + 1이란 연산을 수행했다면 State Logging은 이전 상태와 이후 상태인 0과 1을 저장하고,
Transition Logging은 a = a + 1이란 연산 자체를 저장하는 것이다.
따라서 State Logging의 Undo와 Redo는 이전 이미지와 이후 이미지 자체를 데이터베이스에 반영하는 것이 되고,
Transition Logging은 연산 자체를 수행하거나 역연산을 수행하는 방식으로 Undo와 Redo를 수행하게 된다.
Undo와 Redo 복구 작업에 있어 중요한 점 중 하나는 **멱등성(Idempotent)**이 보장되어야 한다는 점인데, 이는 똑같은 복구작업을 여러번 수행하더라도 같은 결과가 나와야 한다는 것이다.
State Logging의 경우 그 상태 자체를 저장하기 때문에 자연스레 멱등성이 보장된다는 장점이 있지만, Transition Logging은 그렇지 않기 때문에 시스템적으로 여러번 수행되지 않도록 보장할 수 있어야 한다.
한편, Transition Logging이 가지는 장점은 1. 로그 레코드의 크기를 줄일 수 있다는 점(State Logging의 경우 이전 상태의 페이지와 이후 상태 페이지를 모두 저장해야 한다.)과 2. Index와 같이 물리적 구조가 계속 변경되는 자료구조를 복구하기 간편하다는 점이 있다.
예컨데 Index가 변경되며 B+-Tree의 물리적인 레코드의 위치가 계속 변경될 수 있고 Clustered Index의 경우 테이블의 레코드 자체를 물리적으로 재배열할 수 있다.
이럴 경우 로깅 시점과 복구 시점에 데이터의 물리적인 위치가 달라질 수 있다는 걸 의미하는데, State Logging의 경우 물리적 상태 자체를 저장하기 때문에 복구 과정이 그리 간단하지 않다. 반면, Transition Logging의 경우 연산 자체를 저장하기 때문에 좀 더 간단한 과정으로 복구할 수 있다는 것이다.
이를 정리하면
State Logging | Transition Logging |
---|---|
변경 전과 후의 상태를 기록(a=0, a=1) | 변경 연산 자체를 기록(a = a + 1) |
이전과 이후 페이지를 모두 저장해야 함 | 변경 연산 하나만으로 Undo, Redo가 모두 가능(로그 사이즈가 작음) |
멱등성이 보장됨 | 여러번 복구작업이 일어나지 않도록 보장해야 함 |
레코드의 로깅시점과 복구 시점의 물리적 위치가 달라진 경우 복구가 간단하지 않음 | 복구가 간단 |
Log는 언제 쓸까?
로그에 대해 대략 알아보았으니 좀 더 구체적으로 어느 시점에 로그를 쓰는지 알아보도록 하자.
어느 시점에 로그를 쓸지 생각해보려면 로그가 필요한 시점에 대해 생각해보아야 한다.
Undo 작업은 언제 필요한가?
트랜잭션 작업이 아직 완료되지 않고 중단된(실패한) 시점이다.
이미 디스크에 반영된 변경사항을 원본으로 복구해야하기 때문이다. 이말은 즉슨 디스크에 어떤 변경사항을 반영할 때는 어떤 식으로건 이미 Undo Log가 쓰여져 있어야만 한다는 것이다.
이러한 규칙을 WAL(Write Ahead Logging)이라고 부른다. 어떤 상황에서도 디스크에 변경사항을 flush하기 전에 이미 로그가 쓰여져 있어야 한다는 말이다.
똑같이 Redo가 필요한 시점을 생각해보자.
Redo는 트랜잭션의 커밋이 일어난 뒤 아직 디스크에 모든 변경사항이 반영되기 전에 작업이 중단되었을 때 사용한다. 따라서 커밋이 된 시점에는 적어도 모든 Redo Log가 기록되어야만 한다.