[Database] Transaction

AI 개발자 웅이·2022년 8월 18일
0

Database

목록 보기
4/5

Transaction이란?

트랜잭션은 데이터베이스의 상태를 변화시키기 위해 여러 연산들로 구성된 하나의 논리적 작업 단위를 의미한다. 여기서 작업 단위란 사람이 어떤 기준에 따라 직접 하나의 작업을 정한 것을 의미한다.

예를 들어 사용자 A가 B에게 10만원을 송금한다면, DB 작업과 트랜잭션은 아래와 같다.

DB 작업
1. 사용자 A의 계좌에서 10만원이 차감된다.(UPDATE)
2. 사용자 B의 계좌에 10만원이 추가된다.(UPDATE)
트랜잭션
출금 UPDATE 연산 + 입금 UPDATE 연산

위 송금 과정은 10만원이 사용자 A의 계좌에서 출금되고 사용자 B의 계좌에 입금되는 전체 작업이 정상적으로 처리되거나, 정상 처리될 수 없는 경우에는 어느 것도 실행되지 않은 원래 상태로 되돌려져야 한다. 만약 사용자 A의 계좌에서 10만원이 정상적으로 출금되었지만 사용자 B의 계좌에 입금되는 도중 오류가 발생한 상황에서, 이 작업들이 모두 처리가 된다면 매우 큰 문제가 발생할 것이다.

ACID

흔히 트랜잭션은 ACID라고 불리는 네 가지 특징으로 표현된다.

원자성(Atomicity)
DBMS는 완료되지 않은 트랜잭션의 중간 상태를 데이터베이스에 반영하면 안된다. 즉, 트랜잭션을 구성하는 연산들이 DB에 모두 반영되거나 전혀 반영되지 않아야 한다(all or nothing).

일관성(Consistency)
정상적으로 수행된 트랜잭션은 정당한 데이터만을 데이터베이스에 반영해야 한다. 트랜잭션 수행이 보존해야 할 일관성은 기본 키, 외래 키 제약 같은 명시적인 무결성 제약 조건 뿐만 아니라, 출금+입금 전과 후 계좌 잔고의 합이 같이야 한다는 비명시적 조건들도 포함한다.

독립성(Isolation)
여러 트랜잭션이 동시에 수행되더라도 각 트랜잭션이 다른 트랜잭션에 영향을 주지 않아야 한다. 독립성이 깨진다면 트랜잭션이 원래 상태로 돌아갈 수 없게 될 것이다. 독립성을 위해서는 모든 트랜잭션을 순차적으로 처리하면 되지만, 병렬 수행의 시간적 장점 때문에 DBMS는 병렬적으로 트랜잭션을 수행하면서도 독립성이 보장되는 방식을 채택했다.

지속성(Durability)
트랜잭션이 성공적으로 완료되고 나면 해당 트랜잭션은 향후 어떤 소프트웨어나 하드웨어 장애가 발생하더라도 보존되어야 한다.

롤백(Rollback)과 커밋(Commit)

롤백(Rollback) 이란 트랜잭션 도중 에러가 발생하게 되면 트랜잭션의 원자성을 위해 해당 트랜잭션의 모든 작업 연산을 취소하여 실제 데이터베이스에 반영되지 않게 하는 연산이다. 롤백하고 난 후에는 해당 트랜잭션을 재시작하거나 폐기한다.

커밋(Commit) 이란 트랜잭션이 정상적으로 수행되고 일관성이 보장될 때 이를 DB에 알려주기 위해 사용하는 연산이다. 커밋을 해야만 데이터베이스에 변경 사항이 반영된다.

Transaction Status

Active(활동 상태)
트랜잭션이 현재 연산을 수행 중인 상태

Partially Committed(부분 완료 상태)
마지막 연산이 실행된 직후의 상태이며, 연산은 모두 처리되었지만 데이터베이스에는 반영되지 않은 상태

Committed(완료 상태)
트랜잭션이 성공적으로 수행되어 커밋한 상태

Failed(실패 상태)
트랜잭션 도중 장애가 발생하여 중단된 상태

Aborted(철회 상태)
트랜잭션 수행에 실패하여 롤백한 상태

트랜잭션 상태 다이어그램

트랜잭션 관리를 위한 DBMS의 전략

데이터베이스 시스템은 보통 비휘발성 저장 장치인 디스크에 데이터를 저장하며, 전체 데이터베이스의 일부분을 메인 메모리에 유지한다. DBMS는 데이터를 고정 길이인 페이지(page)에 저장하며, 디스크에서 페이지 단위로 입출력이 이루어진다. 메인 메모리에 유지하는 페이지를 관리하는 모듈을 페이지 버퍼 관리자라고 부른다. DBMS는 크게 Query Processor와 Storage System으로 나눌 수 있다.

여기서 버퍼 관리 정책이 트랜잭션 관리에 있어 매우 중요한 결정을 내린다. 실제로 버터 관리 정책에 따라 트랜잭션의 UNDO 복구와 REDO 복구가 요구되거나 그렇지 않게 된다.

UNDO 복구

트랜잭션 수행 중에 수정된 페이지들이 버퍼 관리자의 버퍼 교체 알고리즘에 따라 디스크에 입력될 수 있다. 아직 완료되지 않은 트랜잭션이 수정한 페이지도 디스크에 입력될 수 있는데, 만약 해당 트랜잭션이 정상적으로 종료될 수 없는 경우에는 변경된 페이지들이 전부 원상 복구 되어야 한다. 이러한 복구를 UNDO라고 한다. 수정된 페이지를 디스크에 쓰는 시점을 기준으로 UNDO는 아래와 같은 두 정책으로 나눠어진다.

STEAL: 수정된 페이지를 언제든지 디스크에 쓸 수 있는 정책
¬STEAL: 수정된 페이지를 트랜잭션 종료 시점(EOT)까지 버퍼에 유지하며 디스크에 쓰지 않는 정책

¬STEAL 정책을 사용한다면 UNDO 오퍼레이션이 비교적 단순해지지만(메모리 버퍼에 대해서만 이루어지면 됨) 이 정책은 매우 큰 크기의 메모리 버퍼가 필요하다는 문제를 갖고 있다. 따라서 거의 모든 DBMS가 STEAL 정책을 채택하는데, 이 정책은 UNDO 로깅과 복구를 수반하게 된다.

REDO 복구
REDO 복구는 UNDO 복구의 반대 개념으로, 이미 수행 중이거나 완료된 트랜잭션의 변경 연산을 다시 반복하는 복구 방법이다. REDO 복구도 마찬가지로 버퍼 관리 정책에 영향을 받는데, 트랜잭션이 종료되는 시점에 해당 트랜잭션이 수정한 페이지를 디스크에도 반영할 것인지 여부로 두 가지 정책을 구분한다.

FORCE: 수정했던 모든 페이지를 트랜잭션 커밋 시점에 디스크에 반영하는 정책
¬FORCE: 수정했던 페이지를 트랜잭션 커밋 시점에 디스크에 반영하지 않는 정책

FORCE 정책을 따르면 커밋 시 디스크 상의 DB에 변경 사항이 모두 반영되므로 REDO 복구가 필요없게 된다. ¬FORCE 정책에서는 어떤 일을 했었는지에 대한 로그는 남겨서 변경 사항을 추적한다. ¬FORCE 정책을 따른다면 디스크 상의 DB에 변경 사항이 반영되어 있지 않을 수 있기에 반드시 REDO 복구 필요하다. 거의 모든 DBMS가 채택하는 정책은 ¬FORCE 정책이다.

DBMS가 버퍼 관리 정책으로 STEAL과 ¬FORCE 정책을 채택하고 있기 때문에, UNDO, REDO 복구가 모두 필요해진다.

로그(Log)

로그는 데이터베이스의 모든 변경 작업을 기록한다. 로그는 덧붙이는 방식으로 기록되며, 각 로그 레코드는 고유 식별자를 가진다. 로그 레코드의 식별자를 LSN(Log Sequence Number) 또는 LSA(LOG Sequence Address)라고 부른다. 로그는 항상 덧붙이는 방식이기에 단조 증가하는 성질을 가진다. 로그 데이터는 기록할 내용의 종류에 따라 물리적/논리적 로깅으로 분류할 수 있고, 데이터베이스의 상태 변화를 기록하는지 변화를 야기한 전이를 기록하는지에 따라 State/Transition으로 분류할 수 있다.

Physical State Logging
DBMS에서 가장 빈번하게 사용되는 로깅 방법으로, 로그 레코드에는 변경 이전 이미지와 이후 이미지가 모두 기록된다. UDON 복구 때는 이전 이미지로 현재 이미지를 대체하며, REDO 복구 때는 이후 이미지로 재반영하는 방식으로 복구된다.

Physical Transition Logging
이전/이후 이미지를 모두 기록하지 않고 XOR 차이점을 기록하는 방식으로 기록하는 방법이다. 복구 시점에서 로그 레코드에 기록된 XOR 이미지와 현재 레코드 이미지를 이용하여 UNDO, REDO 복구가 이루어진다.

Logical Transition Logging
Operation Logging이라고도 불리며, 어떤 일을 했는가를 기록하는 방식이다. 예를 들어, a = a + 1 연산을 기록할 때, 이전 값 0, 이후 값 1과 같이 물리적으로 기록할 수 있고, a = a + 1 연산 자체를 기록할 수도 있다. 논리적 로그에 대한 복구 작업은 로그 레코드에 기록된 오퍼레이션을 재수행하여 REDO 복구를 하거나, 역오퍼레이션으로 UNDO 복구를 하는 방식으로 진행된다. 이런 Logical Transition Logging은 각 로그 레코드의 크기를 줄여주는 장점도 있지만, 물리적으로 복구하기 힘든 자료 구조에 대한 로깅을 쉽게 해준다는 장점도 있다. 예를 들어, 인덱스 구조로 많이 사용되는 B+tree의 경우 split, merge와 같은 SMO(Structure Modification Operation)을 통해 데이터의 물리적인 위치가 변할 수 있기 때문에 물리적인 로깅 방식으로 복구하기 힘들지만, 논리적인 로깅 방식으로는 쉽게 복구 가능하다.

로그 작성 규칙

  1. 해당 업데이트가 데이터베이스에 반영되기 전에 관련된 UNDO 정보가 로그에 작성되어야 한다. 이 원칙을 WAL(Write Ahead Logging)이라고 부른다.
  2. 트랜잭션이 정삭적으로 종료 처리되기 되기 위해서는 REDO 정보가 로그에 작성되어야 한다. 따라서 복구를 하기 위해서는 커밋 시점 이전에 REDO 정보가 써져야 한다.

Reference
DBMS는 어떻게 트랜잭션을 관리할까?

profile
저는 AI 개발자 '웅'입니다. AI 연구 및 개발 관련 잡다한 내용을 다룹니다 :)

0개의 댓글