Akashic Records

데이터베이스 트랜젝션(Transactoin) - ACID (Atomicity) 본문

Database Learning Guide

데이터베이스 트랜젝션(Transactoin) - ACID (Atomicity)

Andrew's Akashic Records 2024. 11. 19. 18:31
728x90

데이터베이스에서 트랜잭션(Transaction)은 데이터베이스의 상태를 변화시키는 작업의 논리적인 단위입니다. 일반적으로 트랜잭션은 여러 작업을 하나로 묶어 데이터의 일관성을 보장하는 역할을 합니다. 트랜잭션의 가장 큰 특징은 모든 작업이 성공적으로 완료되거나, 그렇지 않을 경우 모두 원래대로 복구되어야 한다는 점입니다. 이 원칙은 데이터베이스의 무결성과 일관성을 유지하는 데 중요합니다.

 

트랜잭션에는 보통 다음과 같은 4가지 성질이 있습니다. 이를 ACID라고 합니다:

1. Atomicity (원자성)

데이터베이스의 트랜잭션(Transaction)에서 원자성(Atomicity)은 트랜잭션이 모두 성공적으로 완료되거나 전혀 수행되지 않은 것처럼 보장하는 특성을 의미합니다. 이 속성은 데이터베이스의 일관성을 유지하기 위해 매우 중요하며, 다음과 같은 특징을 가집니다.

 

  • All-or-Nothing: 트랜잭션 내에 있는 모든 작업은 모두 실행되거나 전혀 실행되지 않아야 합니다. 트랜잭션이 중간에 실패할 경우, 데이터베이스는 트랜잭션의 어느 부분도 수행되지 않은 상태로 되돌아가야 합니다. 이로 인해 시스템 장애나 에러 상황에서도 데이터의 불일치나 손상이 발생하지 않게 됩니다.
  • Rollback(롤백): 트랜잭션 도중 문제가 발생하거나 실패했을 때, 이미 실행된 모든 연산을 취소하여 이전의 상태로 되돌리는 작업을 의미합니다. 이를 통해 데이터베이스의 상태를 트랜잭션 전의 상태로 복원하여 트랜잭션이 전혀 수행되지 않은 것처럼 처리합니다.
  • Commit(커밋): 트랜잭션의 모든 작업이 성공적으로 완료되었을 때 데이터베이스에 영구적으로 반영하는 작업입니다. 커밋이 성공하면 그 이후에는 해당 트랜잭션의 변경 사항이 유지됩니다.

 

예를 들어 은행에서 계좌 이체를 처리하는 트랜잭션을 생각해 보겠습니다. 만약 A 계좌에서 B 계좌로 100달러를 이체하는 트랜잭션이 있다면, 이 트랜잭션에는 두 가지 중요한 작업이 있습니다:

  1. A 계좌에서 100달러를 출금
  2. B 계좌에 100달러를 입금

원자성에 의해 이 두 작업은 반드시 함께 수행되어야 합니다. 만약 출금 작업이 성공했지만 입금 작업이 실패하면, 트랜잭션은 전체적으로 실패한 것으로 간주하고 롤백하여 A 계좌에서 출금된 100달러도 취소됩니다. 이 과정에서 데이터의 일관성과 정확성을 보장할 수 있습니다.

원자성을 보장하는 메커니즘

원자성을 보장하기 위해 데이터베이스 관리 시스템(DBMS)은 다양한 메커니즘을 사용하여 트랜잭션의 일관성을 유지합니다. 이를 위해 사용되는 주요 메커니즘은 다음과 같습니다:

 

1). 로그(Log) 기반 메커니즘

로그는 트랜잭션 수행 과정에서 발생하는 모든 변경 사항을 기록하는 방법으로, 데이터베이스는 로그를 통해 원자성을 보장합니다. 이 방법은 데이터 손실이나 장애 발생 시 이전 상태로 되돌릴 수 있도록 도와줍니다.

  • Write-Ahead Logging (WAL): WAL은 변경 사항을 실제 데이터에 적용하기 전에 로그 파일에 먼저 기록하는 방법입니다. 이 방식은 데이터 손실이나 오류 발생 시 로그를 이용해 변경된 내용을 롤백하거나 재적용할 수 있게 해줍니다. 즉, 변경 사항을 데이터베이스에 영구 반영하기 전에 안전하게 로그에 기록함으로써 트랜잭션의 원자성을 보장합니다.
  • Undo/Redo 로그: Undo 로그는 트랜잭션이 실패했을 때 변경된 내용을 되돌릴 수 있는 정보를 기록하며, Redo 로그는 성공한 트랜잭션의 내용을 다시 적용하는 정보를 기록합니다. 두 가지 로그 모두 데이터 일관성을 유지하는 데 중요한 역할을 합니다.

2). 체크포인트(Checkpoint)

체크포인트는 데이터베이스가 장애가 발생할 경우, 빠르게 복구할 수 있도록 일정한 시점의 시스템 상태를 저장해두는 메커니즘입니다. 체크포인트 이후의 트랜잭션 기록만을 사용해 복구 작업을 수행함으로써, 시스템이 빠르게 정상 상태로 돌아올 수 있도록 도와줍니다.

 

3). 트랜잭션 관리 시스템(TMS)

DBMS에는 트랜잭션 관리 시스템(Transaction Management System)이 내장되어 있어 각 트랜잭션이 올바르게 처리되도록 관리합니다. 트랜잭션 관리 시스템은 다음을 통해 원자성을 보장합니다.

  • Commit과 Rollback 연산: 트랜잭션이 성공적으로 종료되면 커밋(Commit)을 통해 변경 사항을 영구적으로 저장합니다. 반대로 트랜잭션이 실패할 경우 롤백(Rollback)을 통해 데이터베이스를 트랜잭션 시작 이전 상태로 되돌려 모든 변경 사항을 무효화합니다.

4). 잠금(Locking) 메커니즘

잠금(Lock)은 여러 트랜잭션이 동시에 데이터베이스에 접근할 때 데이터의 일관성을 유지하고, 트랜잭션 간의 충돌을 방지하기 위해 사용됩니다. 원자성을 보장하기 위해 트랜잭션이 완료될 때까지 데이터에 대한 독점적인 잠금을 유지하여, 다른 트랜잭션이 중간 단계에서 해당 데이터에 접근하지 못하도록 합니다.

  • Exclusive Lock (배타적 잠금): 데이터에 대해 하나의 트랜잭션만이 읽기와 쓰기를 수행할 수 있도록 배타적 권한을 부여하는 잠금 방식으로, 이를 통해 트랜잭션 도중 다른 트랜잭션이 변경하지 못하게 하여 원자성을 보장합니다.

5). 복구 매니저(Recovery Manager)

복구 매니저는 시스템 오류나 충돌이 발생했을 때 데이터베이스를 일관된 상태로 복구하는 데 사용됩니다. 복구 매니저는 로그 파일과 체크포인트를 사용하여 트랜잭션이 실패하거나 시스템이 중단되었을 때, 해당 트랜잭션의 모든 작업을 취소하고 트랜잭션 시작 전의 상태로 되돌립니다.

각 데이터베이스의 원자성 구현

데이터베이스 관리 시스템(DBMS)에서 원자성을 보장하기 위한 구현은 각 DBMS의 특성 및 설계에 따라 다소 차이가 있습니다. 아래는 주요 DBMS인 MySQL, PostgreSQL, 그리고 Oracle에서 원자성을 구현하는 방식에 대한 예시입니다.

 

1). MySQL

MySQL은 여러 스토리지 엔진을 제공하지만, InnoDB 엔진이 ACID 속성을 지원하며 원자성을 보장하는 대표적인 예입니다.

InnoDB 엔진의 원자성 구현

  • Redo 및 Undo 로그: InnoDB는 트랜잭션의 원자성을 보장하기 위해 Redo 로그Undo 로그를 사용합니다.
    • Redo 로그는 트랜잭션 커밋 시 데이터를 영구 저장하는 데 필요한 정보를 기록하여 시스템 장애 이후에도 데이터베이스를 복구할 수 있도록 합니다.
    • Undo 로그는 트랜잭션이 실패할 경우, 변경된 데이터를 원래 상태로 되돌리는 정보를 기록합니다. 이를 통해 트랜잭션이 실패해도 그 이전 상태로 복원할 수 있습니다.
  • Write-Ahead Logging (WAL): MySQL InnoDB는 WAL 기법을 사용하여 데이터 변경 전에 먼저 로그를 작성함으로써 트랜잭션의 실패 시 데이터를 복구할 수 있게 합니다. 즉, 트랜잭션의 변경 사항이 데이터 파일에 반영되기 전에 로그가 안전하게 저장되도록 합니다.
  • Crash Recovery: InnoDB는 서버 장애 발생 시 로그 파일을 사용해 장애 이전 상태로 복구합니다. 이 과정에서 Undo 로그를 사용해 모든 실패한 트랜잭션을 롤백하여 원자성을 보장합니다.

 

사용자는 보통 InnoDB의 Undo 로그, Redo 로그, 그리고 WAL 설정을 명시적으로 다룰 필요가 없습니다. MySQL은 기본적으로 InnoDB 엔진에서 이 모든 메커니즘을 자동으로 관리하여 데이터 일관성과 트랜잭션 원자성을 보장합니다.

다만, 로그 파일의 크기로그 보관 주기 같은 설정을 사용자가 조정할 수 있는 옵션이 제공되기는 합니다. 예를 들어 innodb_log_file_size 또는 innodb_log_buffer_size와 같은 파라미터를 통해 로그 관련 설정을 튜닝할 수 있지만, Undo/Redo 로그와 WAL의 사용 자체는 자동입니다.

 

 

2). PostgreSQL

PostgreSQL은 고급 트랜잭션 기능을 제공하는 오픈소스 DBMS로, ACID 속성, 특히 원자성을 엄격히 지원합니다.

PostgreSQL의 원자성 구현

  • WAL (Write-Ahead Logging): PostgreSQL도 WAL 기법을 사용하여 트랜잭션의 변경 사항이 데이터 파일에 반영되기 전에 로그를 기록합니다. 이는 시스템 장애 시 데이터의 원자성을 보장하고, 손실 없이 데이터를 복구하는 데 중요한 역할을 합니다.
  • Multi-Version Concurrency Control (MVCC): PostgreSQL은 MVCC 방식을 통해 트랜잭션이 동시에 실행될 때도 데이터의 일관성과 원자성을 유지합니다. MVCC는 각 트랜잭션이 자신만의 데이터 "스냅샷"을 가지고 작업하도록 하여 중간에 다른 트랜잭션이 변경된 데이터에 영향을 주지 않게 합니다.
  • Crash Recovery: PostgreSQL은 WAL 파일을 사용하여 서버가 비정상적으로 종료된 후에도 데이터베이스를 일관된 상태로 복구합니다. 모든 진행 중인 트랜잭션은 롤백 처리되고, 성공한 트랜잭션은 Redo 단계에서 다시 반영하여 원자성을 보장합니다.
728x90

Multi-Version Concurrency Control (MVCC)

PostgreSQL의 중요한 트랜잭션 관리 기법으로, 데이터베이스에서 동시에 여러 트랜잭션이 접근할 수 있도록 하여 잠금(lock)으로 인한 병목 현상을 줄이고, 일관된 데이터 접근을 가능하게 합니다. MVCC의 가장 큰 특징은 데이터의 여러 버전을 관리하여 트랜잭션 간의 충돌을 줄이고, 데이터 일관성을 유지하는 것입니다. PostgreSQL은 이 방식을 통해 높은 동시성을 제공하면서도 트랜잭션 격리데이터 일관성을 보장합니다.

MVCC의 주요 개념

  1. 다중 버전(Multi-Version):
    • MVCC에서는 데이터의 여러 버전을 유지합니다. 데이터가 업데이트되면 PostgreSQL은 기존 데이터를 바로 덮어쓰지 않고, 새로운 버전의 데이터를 생성합니다. 이 덕분에 트랜잭션이 진행되는 동안 다른 트랜잭션이 동일한 데이터에 접근할 수 있게 됩니다.
    • 기존 트랜잭션이 시작될 때 해당 트랜잭션은 자신만의 "스냅샷"을 통해 데이터의 상태를 유지합니다. 이를 통해 다른 트랜잭션이 데이터를 수정하더라도 현재 트랜잭션에서는 자신이 시작할 당시의 데이터를 계속 읽을 수 있습니다.
  2. 트랜잭션 타임스탬프:
    • 각 트랜잭션에는 고유한 타임스탬프(transaction ID, 또는 TxID)가 부여됩니다. 이 타임스탬프를 기준으로 각 트랜잭션이 데이터의 어떤 버전을 사용할 수 있는지 결정됩니다.
    • 데이터의 행마다 두 개의 특수한 필드, xminxmax가 있습니다. 이 필드는 해당 행을 생성하거나 수정한 트랜잭션의 타임스탬프를 기록하는 데 사용됩니다.
      • xmin: 해당 행을 삽입(insert)한 트랜잭션의 ID를 기록합니다.
      • xmax: 해당 행을 삭제(delete)하거나 업데이트(update)한 트랜잭션의 ID를 기록합니다.
  3. 일관된 읽기(Consistent Reads):
    • 트랜잭션이 시작될 때 그 트랜잭션은 시작 시점의 데이터 스냅샷을 통해 데이터를 읽습니다. 다른 트랜잭션에서 데이터의 새로운 버전을 작성하더라도, 현재 트랜잭션은 기존의 데이터 버전을 계속 읽을 수 있습니다.
    • 예를 들어, 트랜잭션 A가 테이블에서 데이터를 읽고 있는 동안 트랜잭션 B가 동일한 데이터를 수정한다면, 트랜잭션 A는 수정되기 이전의 데이터를 읽을 수 있습니다. 이는 트랜잭션 B가 데이터를 수정하면서 새 버전을 생성하고, 기존 버전을 그대로 유지하기 때문입니다.

MVCC의 트랜잭션 격리 수준

PostgreSQL에서 MVCC는 다양한 트랜잭션 격리 수준을 지원하여 트랜잭션이 동시 접근을 처리하는 방식을 조정할 수 있습니다:

  1. Read Uncommitted:
    • 이 수준에서는 트랜잭션이 아직 커밋되지 않은 데이터를 읽을 수 있습니다. 하지만 PostgreSQL의 MVCC 특성상, 실제로는 기본적으로 Read Committed 수준을 제공합니다.
  2. Read Committed:
    • 가장 일반적인 격리 수준으로, 트랜잭션은 커밋된 데이터만 읽을 수 있습니다. 다른 트랜잭션에서 커밋된 변경 사항은 즉시 반영되므로, 트랜잭션이 진행 중일 때 새로운 데이터가 나타날 수 있습니다.
  3. Repeatable Read:
    • 이 수준에서는 트랜잭션이 시작된 후에 읽은 데이터가 변경되지 않음을 보장합니다. 트랜잭션 중간에 다른 트랜잭션이 데이터에 변경을 가해도, 현재 트랜잭션은 그 변화를 볼 수 없습니다.
    • 이 격리 수준에서는 팬텀 리드(Phantom Read)가 발생하지 않습니다. 즉, 반복적으로 같은 쿼리를 실행할 때, 데이터가 추가되거나 삭제되지 않습니다.
  4. Serializable:
    • 가장 엄격한 격리 수준으로, 트랜잭션 간의 상호작용을 완전히 차단합니다. 트랜잭션이 동시에 실행되더라도, 서로의 영향을 받지 않는 것처럼 보입니다. 데이터 일관성은 완벽히 유지되지만, 성능에는 영향을 줄 수 있습니다.

MVCC의 작동 방식

  1. 데이터 삽입(INSERT):
    • 새로운 트랜잭션이 데이터를 삽입할 때, 해당 행의 xmin 필드에 삽입을 수행한 트랜잭션의 ID가 기록됩니다. 이 데이터는 다른 트랜잭션이 볼 수 없으며, 삽입한 트랜잭션이 커밋되면 그 이후의 트랜잭션에서 접근 가능하게 됩니다.
  2. 데이터 수정(UPDATE):
    • 데이터가 수정되면 PostgreSQL은 기존 행을 삭제하는 대신, 새로운 버전의 행을 생성합니다. 기존 행의 xmax 필드에는 수정 트랜잭션의 ID가 기록되고, 새로운 행의 xmin 필드에는 새로운 트랜잭션 ID가 기록됩니다.
    • 이 방식으로, 다른 트랜잭션은 수정되기 이전의 데이터를 계속해서 읽을 수 있습니다.
  3. 데이터 삭제(DELETE):
    • 데이터가 삭제될 때도 행 자체가 즉시 제거되지 않습니다. 삭제된 행의 xmax 필드에 삭제를 수행한 트랜잭션의 ID가 기록됩니다. 트랜잭션이 커밋되면 삭제된 데이터는 "보이지 않는" 상태가 되지만, 아직 트랜잭션이 완료되지 않았다면 다른 트랜잭션에서는 해당 데이터를 계속 읽을 수 있습니다.

MVCC의 장점과 단점

  • 장점:
    • 높은 동시성 지원: MVCC는 여러 트랜잭션이 동시에 데이터에 접근해도, 각 트랜잭션이 독립적인 데이터 "스냅샷"을 사용하기 때문에 잠금으로 인한 병목 현상이 줄어듭니다.
    • 일관된 읽기 제공: 트랜잭션 중에 다른 트랜잭션의 영향 없이 일관된 데이터를 읽을 수 있어 데이터 일관성 유지가 쉽습니다.
  • 단점:
    • 오버헤드 증가: 여러 버전의 데이터를 유지해야 하므로 디스크 공간이 더 많이 필요하며, 불필요해진 데이터 버전을 주기적으로 정리하는 VACUUM 작업이 필요합니다.
    • VACUUM의 필요성: 사용되지 않는 오래된 데이터 버전을 정리해야 하는데, 이를 위해 주기적으로 VACUUM 명령을 실행해야 합니다. VACUUM을 통해 삭제된 데이터와 업데이트로 인해 생긴 이전 버전을 제거하여 공간을 확보하고, 데이터베이스 성능을 유지합니다.

 

3). Oracle

Oracle Database는 고도의 안정성을 제공하는 DBMS로, 다양한 방법을 통해 원자성을 보장합니다.

Oracle의 원자성 구현

  • Redo 및 Undo 로그: Oracle은 Redo 로그Undo 세그먼트를 사용하여 트랜잭션의 원자성을 보장합니다.
    • Undo 세그먼트: 트랜잭션 중 변경된 데이터의 이전 버전을 저장하여, 트랜잭션이 롤백될 때 이전 상태로 복구할 수 있습니다.
    • Redo 로그: 트랜잭션 커밋 시 변경된 내용을 로그에 기록하여 장애 발생 시 이를 사용해 데이터베이스를 복구합니다.
  • Automatic Undo Management: Oracle은 Automatic Undo Management 기능을 통해 트랜잭션이 실행되는 동안 필요한 Undo 정보를 관리합니다. 이를 통해 트랜잭션 실패 시 자동으로 변경 사항을 되돌릴 수 있게 하여 원자성을 보장합니다.
  • Flashback Technology: Oracle의 Flashback 기능은 특정 시점의 데이터를 복구하거나 트랜잭션을 취소하는 데 사용됩니다. 이 기능은 사용자가 실수로 잘못된 데이터를 업데이트하거나 삭제한 경우 원래 상태로 되돌리는 데 도움이 됩니다.

Automatic Undo Management (AUM)

AUM은 Undo Tablespace라는 전용 테이블 공간을 사용하여 트랜잭션 동안 생성되는 Undo 데이터를 관리합니다. 이 방식은 Oracle이 자동으로 Undo 세그먼트를 할당하고 관리할 수 있도록 해줍니다.

  1. Undo Tablespace:
    • Undo Tablespace는 Undo 데이터를 저장하기 위해 특별히 설계된 테이블 공간입니다. Oracle 데이터베이스는 모든 트랜잭션을 위한 Undo 데이터를 이 테이블 공간에 기록합니다.
  2. 자동으로 Undo 세그먼트 관리:
    • AUM에서는 사용자가 직접 Undo 세그먼트를 생성하거나 관리할 필요가 없습니다. Oracle 데이터베이스가 자동으로 필요한 Undo 세그먼트를 생성하고, 트랜잭션에 필요한 양을 할당합니다.
    • 이러한 자동화된 방식으로 인해, 사용자는 Undo 공간의 크기나 상태를 걱정할 필요 없이 데이터베이스가 성능을 최적화할 수 있습니다.
  3. 데이터 읽기 일관성(Read Consistency):
    • AUM은 트랜잭션이 데이터베이스의 데이터를 읽을 때, 해당 데이터가 다른 트랜잭션에 의해 변경되었더라도 원래 데이터 버전을 제공하여 트랜잭션 격리성을 유지합니다.
    • 이를 위해 Undo 데이터를 사용하여 데이터의 변경 전 상태를 다른 트랜잭션에서 일관되게 읽을 수 있도록 합니다.
  4. 자동 공간 확보 및 재사용:
    • Oracle은 자동으로 사용되지 않는 Undo 데이터를 모니터링하고, 필요에 따라 공간을 확보합니다. 이는 데이터베이스가 공간을 효과적으로 관리하여 부족한 Undo 공간으로 인한 오류를 방지합니다.
    • 데이터베이스는 트랜잭션이 커밋되면 해당 Undo 데이터를 필요에 따라 재사용할 수 있으며, 이를 통해 효율적인 공간 활용이 가능합니다.

AUM의 작동 방식

  1. 트랜잭션 시작:
    • 트랜잭션이 시작되면, 데이터베이스는 Undo Tablespace에서 Undo 세그먼트를 할당받습니다. 트랜잭션이 데이터베이스를 변경할 때, 변경되기 이전 데이터의 스냅샷이 Undo 세그먼트에 저장됩니다.
  2. 데이터 변경과 Undo 데이터 생성:
    • 데이터가 변경될 때, Oracle은 변경 전 데이터의 복사본을 Undo Tablespace에 저장합니다. 이 데이터는 롤백이 필요하거나 다른 트랜잭션이 일관된 읽기를 수행해야 할 때 사용됩니다.
  3. 트랜잭션 완료(커밋/롤백):
    • 커밋: 트랜잭션이 성공적으로 완료되면, 해당 Undo 데이터는 일정 기간 동안 보관된 후 재사용 가능하게 됩니다. 이는 다른 트랜잭션이 해당 데이터에 접근할 수 있도록 읽기 일관성을 제공하는 데 사용됩니다.
    • 롤백: 트랜잭션이 실패하거나 사용자가 롤백을 요청하면, Undo 데이터를 사용하여 트랜잭션의 모든 변경 사항을 이전 상태로 복구합니다.
  4. Undo Retention:
    • Oracle AUM에서는 Undo Retention이라는 메커니즘을 통해, 트랜잭션 커밋 후에도 일정 시간 동안 Undo 데이터를 보존하여 읽기 일관성을 유지합니다.
    • UNDO_RETENTION 파라미터를 통해 이 보존 시간을 설정할 수 있으며, 이 시간을 기준으로 데이터가 보존된 후에야 비로소 재사용될 수 있습니다.
    • 예를 들어, 분석 쿼리나 긴 조회 작업이 수행될 때 UNDO_RETENTION 시간을 충분히 길게 설정하면, 해당 작업 중에 다른 트랜잭션이 데이터를 변경하더라도 원래 상태의 데이터에 접근할 수 있게 됩니다.

AUM의 주요 장점

  1. 관리의 단순화:
    • 사용자는 Undo 공간을 직접 관리할 필요 없이 데이터베이스가 자동으로 필요한 Undo 세그먼트를 생성하고 관리하므로, 관리의 복잡성이 크게 줄어듭니다.
  2. 효율적인 공간 활용:
    • 필요하지 않은 Undo 데이터는 자동으로 재사용되며, 데이터베이스는 공간을 효율적으로 관리하여 성능 문제를 방지합니다.
  3. 트랜잭션 일관성 유지:
    • AUM은 자동으로 트랜잭션 간의 읽기 일관성을 보장하여, 각 트랜잭션이 독립적인 상태로 데이터에 접근할 수 있도록 합니다. 이는 데이터의 무결성과 신뢰성을 유지하는 데 중요한 역할을 합니다.
  4. Undo Retention 설정을 통한 유연성:
    • UNDO_RETENTION 파라미터를 통해 오래된 데이터의 유지 기간을 설정함으로써, 긴 쿼리나 리포트 작성 시 데이터 일관성을 보장할 수 있습니다.

2. Consistency (일관성)

데이터베이스 트랜젝션(Transactoin) - ACID (Consistency)

3. Isolation(격리성)

데이터베이스 트랜젝션(Transactoin) - ACID (Isolation)

4. Durability(지속성)

데이터베이스 트랜젝션(Transactoin) - ACID (Durability)

Database Transaction

728x90
Comments