원자성 (Atomicity)
개요
원자성(Atomicity)이란 데이터베이스 트랜잭션(Transaction, 하나의 논리적 기능을 수행하기 위한 작업의 단위) 내의 모든 연산이 모두 성공적으로 반영되거나, 아니면 전혀 반영되지 않아야 함을 보장하는 성질이다.
이는 흔히 'All or Nothing' 원칙으로 설명된다. 트랜잭션 내에 포함된 여러 단계의 작업 중 단 하나라도 실패할 경우, 전체 트랜잭션을 취소하여 데이터베이스를 트랜잭션 시작 전의 상태로 되돌림으로써 데이터의 부분적 업데이트로 인한 부정합을 방지하는 것이 핵심 목적이다.
작동 원리 및 메커니즘
원자성을 구현하기 위해 데이터베이스 관리 시스템(DBMS)은 트랜잭션의 종료 상태를 결정하는 두 가지 핵심 메커니즘인 커밋과 롤백을 사용한다.
- 커밋 (Commit): 트랜잭션 내의 모든 작업이 성공적으로 완료되었음을 확정 짓는 명령이다. 커밋이 수행되면 변경 사항이 데이터베이스에 영구적으로 저장되며, 다른 사용자나 트랜잭션이 해당 변경 내용을 볼 수 있게 된다.
- 롤백 (Rollback): 트랜잭션 실행 중 오류가 발생하거나 사용자가 취소를 요청했을 때, 지금까지 수행한 모든 변경 사항을 취소하고 트랜잭션 시작 전의 상태로 되돌리는 명령이다.
[표 1] 커밋과 롤백의 비교
| 구분 |
커밋 (Commit) |
롤백 (Rollback) |
| 결과 |
변경 사항의 영구 반영 |
변경 사항의 완전한 취소 |
| 상태 변화 |
트랜잭션 완료 $\rightarrow$ 확정 상태 |
트랜잭션 실패 $\rightarrow$ 이전 상태 복구 |
| 데이터 영향 |
데이터베이스에 최종 기록됨 |
데이터베이스에 영향 없음 (원복) |
| 발생 시점 |
모든 연산이 성공적으로 종료되었을 때 |
런타임 에러, 제약 조건 위반, 사용자 취소 시 |
또한, 원자성이 보장되더라도 트랜잭션 격리 수준(Isolation Level)에 따라 다른 트랜잭션이 '원자적으로 처리 중인' 중간 단계의 데이터를 조회하는 현상(Dirty Read 등)이 발생할 수 있다. 이는 원자성 자체의 결함이라기보다 격리성 설정에 따른 결과이며, 이를 통해 원자적 실행의 외관을 얼마나 엄격하게 유지할지가 결정된다.
원자성 보장을 위한 기술적 구현
DBMS는 시스템 장애나 예기치 못한 오류 상황에서도 원자성을 유지하기 위해 로그(Log) 기반의 복구 메커니즘을 사용한다.
Undo 로그는 데이터를 변경하기 전의 이전 값을 기록하는 로그이다. 트랜잭션이 롤백되어야 할 때, DBMS는 이 Undo 로그를 참조하여 변경된 데이터를 원래 상태로 되돌린다.
Redo 로그는 변경된 후의 값을 기록하는 로그이다. 시스템 장애로 인해 메모리에만 반영되고 디스크에 기록되지 않은 커밋된 데이터를 복구하여 지속성(Durability)을 보장하는 데 사용된다.
[표 2] Undo 로그와 Redo 로그의 비교
| 구분 |
Undo 로그 (Undo Log) |
Redo 로그 (Redo Log) |
| 기록 내용 |
변경 전 데이터 (Before Image) |
변경 후 데이터 (After Image) |
| 주요 목적 |
트랜잭션 취소 및 원복 (Rollback) |
장애 발생 시 데이터 재현 (Recovery) |
| 관련 특성 |
원자성 (Atomicity) |
지속성 (Durability) |
| 작동 시점 |
롤백 수행 시 또는 읽기 일관성 유지 시 |
시스템 재시작 시 복구 과정에서 수행 |
WAL(로그 선행 기입) 방식은 실제 데이터 페이지를 디스크에 쓰기 전에, 변경 사항을 먼저 로그 파일에 기록하는 기법이다.
1. 변경 사항을 메모리(Buffer Pool)에 반영하고 로그 파일에 기록한다.
2. 시스템 장애 발생 시, DBMS는 디스크에 저장된 로그를 분석하여 커밋되지 않은 트랜잭션을 식별하고, 이를 Undo 하여 원자성을 회복한다. 즉, '로그를 먼저 쓰고 데이터를 나중에 쓴다'는 순서 보장을 통해 장애 상황에서도 완전한 롤백이 가능하게 한다.
실제 적용 사례 및 위반 시 문제점
계좌 이체 예시
계좌 이체는 '출금'과 '입금'이라는 두 가지 작업이 반드시 하나의 단위로 묶여야 하는 대표적인 사례이다.
- 정상 흐름: A 계좌에서 10,000원 차감 $\rightarrow$ B 계좌에 10,000원 추가 $\rightarrow$ Commit
- 원자성 위반 사례: A 계좌에서 10,000원이 차감되었으나, 네트워크 오류로 인해 B 계좌에 입금되기 전 시스템이 다운된 경우.
- 결과: A의 돈은 사라졌지만 B는 받지 못한 상태가 되어 데이터 무결성이 파괴된다.
- 해결: 원자성이 보장된다면, 입금 실패 시 출금 내역까지 모두 Rollback 하여 A의 잔액을 원래대로 복구한다.
SQL 구현 예제
-- 트랜잭션 시작
BEGIN TRANSACTION;
-- 1. A 계좌에서 출금
UPDATE Accounts SET balance = balance - 10000 WHERE account_id = 'A';
-- 2. B 계좌에 입금
UPDATE Accounts SET balance = balance + 10000 WHERE account_id = 'B';
-- [시나리오 A] 모든 과정이 성공한 경우
COMMIT;
-- [시나리오 B] 중간에 오류 발생 시 롤백 수행
-- ROLLBACK;
분산 시스템의 원자성
2단계 커밋 (2PC, Two-Phase Commit)
여러 개의 분산 데이터베이스에 걸쳐 트랜잭션이 일어날 경우, 모든 노드가 동시에 커밋하거나 롤백해야 한다. 이를 위해 2단계 커밋(2PC) 프로토콜을 사용한다.
- 준비 단계 (Prepare Phase): 조정자(Coordinator)가 모든 참여 노드(Participant)에게 준비 여부를 묻는다. 각 노드는 변경 사항을 로그에 기록하고 "준비 완료(Ready)" 또는 "실패(Abort)" 응답을 보낸다.
- 커밋 단계 (Commit Phase):
- 모든 노드가 "준비 완료"를 응답하면, 조정자는 모든 노드에 Commit 명령을 내린다.
- 단 하나라도 "실패"를 응답하거나 응답이 없으면, 조정자는 모든 노드에 Rollback 명령을 내려 원자성을 유지한다.
2PC는 강력한 원자성을 보장하지만, 모든 노드가 응답할 때까지 자원을 점유하는 블로킹(Blocking) 문제와 조정자 노드에 장애가 발생할 경우 전체 시스템이 마비되는 단일 장애점(SPOF) 문제가 있다.
이를 해결하기 위해 마이크로서비스 아키텍처(MSA)에서는 Saga 패턴을 대안으로 사용한다. Saga 패턴은 하나의 거대한 트랜잭션을 여러 개의 로컬 트랜잭션으로 나누어 순차적으로 실행하며, 중간에 실패할 경우 이미 성공한 작업들을 취소하는 보상 트랜잭션(Compensating Transaction)을 실행하여 결과적인 원자성(Eventual Consistency)을 달성한다.
ACID 특성 내에서의 관계
원자성은 ACID(Atomicity, Consistency, Isolation, Durability) 모델의 첫 번째 요소로, 다른 특성들과 상호작용하여 데이터 무결성을 유지한다.
- 원자성 $\rightarrow$ 일관성: 원자성이 보장되어 '부분적 업데이트'가 일어나지 않아야만, 데이터베이스가 정의된 규칙(제약 조건)을 만족하는 일관된 상태를 유지할 수 있다.
- 원자성 $\rightarrow$ 격리성: 격리성은 트랜잭션이 수행 중인 중간 상태(원자성이 아직 완성되지 않은 상태)를 다른 트랜잭션이 보지 못하게 하여, 외부에서 보기에 트랜잭션이 한 번에 일어난 것처럼 보이게 함으로써 원자적 실행의 외관을 유지한다.
- 원자성 $\rightarrow$ 지속성: 커밋된 트랜잭션의 결과는 시스템 장애가 발생하더라도 영구적으로 보존되어야 하며, 이는 WAL과 Redo 로그를 통해 구현된다.
[표 3] 원자성(Atomicity)과 일관성(Consistency)의 차이
| 구분 |
원자성 (Atomicity) |
일관성 (Consistency) |
| 핵심 개념 |
"전부 아니면 전무 (All or Nothing)" |
"정해진 규칙의 준수 (Correctness)" |
| 초점 |
트랜잭션의 완결성 (작업 단위의 성공 여부) |
트랜잭션 전후의 데이터 상태 (무결성 제약 조건) |
| 실패 시 결과 |
작업 내용을 모두 취소하고 이전으로 복구 |
제약 조건 위반 시 트랜잭션을 거부하거나 롤백 |
| 비유 |
이체 과정 중 사고 나면 돈을 돌려줌 |
이체 후 총 금액의 합계가 변하지 않아야 함 |
# 원자성 (Atomicity)
## 개요
**원자성(Atomicity)**이란 데이터베이스 트랜잭션(Transaction, 하나의 논리적 기능을 수행하기 위한 작업의 단위) 내의 모든 연산이 모두 성공적으로 반영되거나, 아니면 전혀 반영되지 않아야 함을 보장하는 성질이다.
이는 흔히 **'All or Nothing'** 원칙으로 설명된다. 트랜잭션 내에 포함된 여러 단계의 작업 중 단 하나라도 실패할 경우, 전체 트랜잭션을 취소하여 데이터베이스를 트랜잭션 시작 전의 상태로 되돌림으로써 데이터의 부분적 업데이트로 인한 부정합을 방지하는 것이 핵심 목적이다.
## 작동 원리 및 메커니즘
원자성을 구현하기 위해 데이터베이스 관리 시스템(DBMS)은 트랜잭션의 종료 상태를 결정하는 두 가지 핵심 메커니즘인 커밋과 롤백을 사용한다.
* **커밋 (Commit):** 트랜잭션 내의 모든 작업이 성공적으로 완료되었음을 확정 짓는 명령이다. 커밋이 수행되면 변경 사항이 데이터베이스에 영구적으로 저장되며, 다른 사용자나 트랜잭션이 해당 변경 내용을 볼 수 있게 된다.
* **롤백 (Rollback):** 트랜잭션 실행 중 오류가 발생하거나 사용자가 취소를 요청했을 때, 지금까지 수행한 모든 변경 사항을 취소하고 트랜잭션 시작 전의 상태로 되돌리는 명령이다.
### [표 1] 커밋과 롤백의 비교
| 구분 | 커밋 (Commit) | 롤백 (Rollback) |
| :--- | :--- | :--- |
| **결과** | 변경 사항의 영구 반영 | 변경 사항의 완전한 취소 |
| **상태 변화** | 트랜잭션 완료 $\rightarrow$ 확정 상태 | 트랜잭션 실패 $\rightarrow$ 이전 상태 복구 |
| **데이터 영향** | 데이터베이스에 최종 기록됨 | 데이터베이스에 영향 없음 (원복) |
| **발생 시점** | 모든 연산이 성공적으로 종료되었을 때 | 런타임 에러, 제약 조건 위반, 사용자 취소 시 |
또한, 원자성이 보장되더라도 **트랜잭션 격리 수준(Isolation Level)**에 따라 다른 트랜잭션이 '원자적으로 처리 중인' 중간 단계의 데이터를 조회하는 현상(Dirty Read 등)이 발생할 수 있다. 이는 원자성 자체의 결함이라기보다 격리성 설정에 따른 결과이며, 이를 통해 원자적 실행의 외관을 얼마나 엄격하게 유지할지가 결정된다.
## 원자성 보장을 위한 기술적 구현
DBMS는 시스템 장애나 예기치 못한 오류 상황에서도 원자성을 유지하기 위해 로그(Log) 기반의 복구 메커니즘을 사용한다.
### Undo 로그 (Undo Log)
Undo 로그는 데이터를 변경하기 전의 이전 값을 기록하는 로그이다. 트랜잭션이 롤백되어야 할 때, DBMS는 이 Undo 로그를 참조하여 변경된 데이터를 원래 상태로 되돌린다.
### Redo 로그 (Redo Log)
Redo 로그는 변경된 후의 값을 기록하는 로그이다. 시스템 장애로 인해 메모리에만 반영되고 디스크에 기록되지 않은 커밋된 데이터를 복구하여 지속성(Durability)을 보장하는 데 사용된다.
### [표 2] Undo 로그와 Redo 로그의 비교
| 구분 | Undo 로그 (Undo Log) | Redo 로그 (Redo Log) |
| :--- | :--- | :--- |
| **기록 내용** | 변경 전 데이터 (Before Image) | 변경 후 데이터 (After Image) |
| **주요 목적** | 트랜잭션 취소 및 원복 (Rollback) | 장애 발생 시 데이터 재현 (Recovery) |
| **관련 특성** | **원자성 (Atomicity)** | **지속성 (Durability)** |
| **작동 시점** | 롤백 수행 시 또는 읽기 일관성 유지 시 | 시스템 재시작 시 복구 과정에서 수행 |
### Write-Ahead Logging (WAL)
**WAL(로그 선행 기입)** 방식은 실제 데이터 페이지를 디스크에 쓰기 전에, 변경 사항을 먼저 로그 파일에 기록하는 기법이다.
1. 변경 사항을 메모리(Buffer Pool)에 반영하고 로그 파일에 기록한다.
2. 시스템 장애 발생 시, DBMS는 디스크에 저장된 로그를 분석하여 커밋되지 않은 트랜잭션을 식별하고, 이를 Undo 하여 원자성을 회복한다. 즉, '로그를 먼저 쓰고 데이터를 나중에 쓴다'는 순서 보장을 통해 장애 상황에서도 완전한 롤백이 가능하게 한다.
## 실제 적용 사례 및 위반 시 문제점
### 계좌 이체 예시
계좌 이체는 '출금'과 '입금'이라는 두 가지 작업이 반드시 하나의 단위로 묶여야 하는 대표적인 사례이다.
* **정상 흐름:** A 계좌에서 10,000원 차감 $\rightarrow$ B 계좌에 10,000원 추가 $\rightarrow$ **Commit**
* **원자성 위반 사례:** A 계좌에서 10,000원이 차감되었으나, 네트워크 오류로 인해 B 계좌에 입금되기 전 시스템이 다운된 경우.
* **결과:** A의 돈은 사라졌지만 B는 받지 못한 상태가 되어 데이터 무결성이 파괴된다.
* **해결:** 원자성이 보장된다면, 입금 실패 시 출금 내역까지 모두 **Rollback** 하여 A의 잔액을 원래대로 복구한다.
### SQL 구현 예제
```sql
-- 트랜잭션 시작
BEGIN TRANSACTION;
-- 1. A 계좌에서 출금
UPDATE Accounts SET balance = balance - 10000 WHERE account_id = 'A';
-- 2. B 계좌에 입금
UPDATE Accounts SET balance = balance + 10000 WHERE account_id = 'B';
-- [시나리오 A] 모든 과정이 성공한 경우
COMMIT;
-- [시나리오 B] 중간에 오류 발생 시 롤백 수행
-- ROLLBACK;
```
## 분산 시스템의 원자성
### 2단계 커밋 (2PC, Two-Phase Commit)
여러 개의 분산 데이터베이스에 걸쳐 트랜잭션이 일어날 경우, 모든 노드가 동시에 커밋하거나 롤백해야 한다. 이를 위해 **2단계 커밋(2PC)** 프로토콜을 사용한다.
1. **준비 단계 (Prepare Phase):** 조정자(Coordinator)가 모든 참여 노드(Participant)에게 준비 여부를 묻는다. 각 노드는 변경 사항을 로그에 기록하고 "준비 완료(Ready)" 또는 "실패(Abort)" 응답을 보낸다.
2. **커밋 단계 (Commit Phase):**
* 모든 노드가 "준비 완료"를 응답하면, 조정자는 모든 노드에 **Commit** 명령을 내린다.
* 단 하나라도 "실패"를 응답하거나 응답이 없으면, 조정자는 모든 노드에 **Rollback** 명령을 내려 원자성을 유지한다.
### 2PC의 한계와 Saga 패턴
2PC는 강력한 원자성을 보장하지만, 모든 노드가 응답할 때까지 자원을 점유하는 **블로킹(Blocking)** 문제와 조정자 노드에 장애가 발생할 경우 전체 시스템이 마비되는 **단일 장애점(SPOF)** 문제가 있다.
이를 해결하기 위해 마이크로서비스 아키텍처(MSA)에서는 **Saga 패턴**을 대안으로 사용한다. Saga 패턴은 하나의 거대한 트랜잭션을 여러 개의 로컬 트랜잭션으로 나누어 순차적으로 실행하며, 중간에 실패할 경우 이미 성공한 작업들을 취소하는 **보상 트랜잭션(Compensating Transaction)**을 실행하여 결과적인 원자성(Eventual Consistency)을 달성한다.
## ACID 특성 내에서의 관계
원자성은 ACID(Atomicity, Consistency, Isolation, Durability) 모델의 첫 번째 요소로, 다른 특성들과 상호작용하여 데이터 무결성을 유지한다.
* **원자성 $\rightarrow$ 일관성:** 원자성이 보장되어 '부분적 업데이트'가 일어나지 않아야만, 데이터베이스가 정의된 규칙(제약 조건)을 만족하는 일관된 상태를 유지할 수 있다.
* **원자성 $\rightarrow$ 격리성:** 격리성은 트랜잭션이 수행 중인 중간 상태(원자성이 아직 완성되지 않은 상태)를 다른 트랜잭션이 보지 못하게 하여, 외부에서 보기에 트랜잭션이 한 번에 일어난 것처럼 보이게 함으로써 원자적 실행의 외관을 유지한다.
* **원자성 $\rightarrow$ 지속성:** 커밋된 트랜잭션의 결과는 시스템 장애가 발생하더라도 영구적으로 보존되어야 하며, 이는 WAL과 Redo 로그를 통해 구현된다.
### [표 3] 원자성(Atomicity)과 일관성(Consistency)의 차이
| 구분 | 원자성 (Atomicity) | 일관성 (Consistency) |
| :--- | :--- | :--- |
| **핵심 개념** | "전부 아니면 전무 (All or Nothing)" | "정해진 규칙의 준수 (Correctness)" |
| **초점** | 트랜잭션의 **완결성** (작업 단위의 성공 여부) | 트랜잭션 전후의 **데이터 상태** (무결성 제약 조건) |
| **실패 시 결과** | 작업 내용을 모두 취소하고 이전으로 복구 | 제약 조건 위반 시 트랜잭션을 거부하거나 롤백 |
| **비유** | 이체 과정 중 사고 나면 돈을 돌려줌 | 이체 후 총 금액의 합계가 변하지 않아야 함 |