F-LAB JAVA · 6주차 · Phase 6 · 트랜잭션과 ACID
★ 깊이 파기 — ACID 의 마지막, "Commit 은 영원하다"
이 Unit을 끝내면 다음을 답할 수 있어야 한다.
Durability (지속성) 는 commit 된 트랜잭션이 시스템 장애 (전원 차단·OS 크래시) 후에도 영구 보존되어야 한다는 성질로, 메모리 캐시만으로는 부족하고 WAL (Write-Ahead Logging) 을 fsync 로 디스크에 강제 기록해야 보장되며 그래서 ACID 중 디스크 I/O 비용이 가장 큰 성질이다.
Durability (지속성) 는 commit 된 트랜잭션의 변경이 시스템 장애 후에도 영구 보존 되어야 한다는 ACID 의 마지막 성질이다.
단순히 "디스크에 저장" 하면 될 것 같지만 복잡한 이유는 — DB 가 성능을 위해 메모리 캐시 (버퍼 풀) 에 변경을 모아 두고 나중에 디스크로 쓰기 때문이며, 캐시만 있는 상태에서 전원이 나가면 데이터가 사라진다.
해결은 WAL (Write-Ahead Logging) — 데이터 변경 전에 변경 로그를 먼저 디스크에 강제 기록 (fsync) 하여, 시스템 다운 후 재시작 시 로그를 보고 미반영 변경을 다시 적용 (Redo) 한다.
그래서 Durability 는 ACID 중 가장 비싼 성질 — 매 commit 마다 디스크 fsync 가 필요해 I/O 비용이 크고, MySQL 의innodb_flush_log_at_trx_commit같은 설정으로 안전성과 성능을 조절한다.
Durability = 영수증 + 거래 원장:
문제 — 메모리만 (휘발성):
- 거래는 일단 메모장에 (캐시)
- 빠르지만 정전이면 다 사라짐
- 휘발성
해결 — 거래 원장 (WAL):
- 거래 즉시 원장 (로그) 에 기록
- 원장은 영구 (디스크)
- 정전 후에도 원장 봄
- 미반영 거래 다시 처리
fsync:
- 원장에 잉크가 마를 때까지 기다림
- "확실히 적힘" 보장
- 안 그러면 정전 시 사라질 수
- 매 commit 마다 (비쌈)
Redo Log:
- 거래 원장 = Redo Log
- "이렇게 변경했음" 기록
- 장애 후 다시 (재실행)
체크포인트:
- 주기적으로 데이터 디스크에
- 원장 정리 가능
- 복구 시간 ↓
ACID 가장 비쌈:
- 매 commit fsync (디스크 I/O)
- 다른 성질은 메모리 위주
- Durability 만 디스크 강제
→ Durability = WAL + fsync 로 시스템 장애 후에도 commit 보존, 가장 비싼 성질.
1. Durability 정의
2. 영구 보존의 의미
3. 메모리 캐시의 문제
4. WAL (Write-Ahead Logging)
5. fsync
6. 시스템 장애 후 복구
7. Redo Log와 체크포인트
8. ACID 중 가장 비싼
9. 설정과 트레이드오프
Durability (지속성):
Commit 된 트랜잭션은:
- 영구 보존
- 시스템 장애 후에도
- 사라지지 않음
보장 범위:
- 전원 차단 (정전)
- OS 크래시
- DB 프로세스 다운
- 디스크 일부 손상 (RAID/replicas)
→ 모든 장애에서 보장
"Commit" 의 약속:
commit 응답 → 사용자에게 "확정":
- 시스템이 약속
- 어떤 일이 있어도 보존
- 신뢰
→ commit = 영원
Durability (ILIC)
ILIC 결제 시나리오:
- 사용자 결제 완료
- "결제 완료" 응답
- 직후 서버 다운
- 재시작 후?
Durability 보장:
- 결제 기록 살아있음 (영구)
- 사용자는 안심
Durability 없으면:
- 결제 사라짐 (사고)
- 신뢰 ↓
→ ILIC 같은 B2B 에 필수
Durability (지속성) 의 정의는?
답:
1. 정의:
범위:
약속:
목적:
영구:
영원히:
- 다음 트랜잭션이 수정 안 하는 한
- 시스템 다운 후에도
- DB 가 다시 살아나면 거기 있음
vs 휘발성:
휘발성 (메모리):
- 전원 차단 → 사라짐
- RAM, CPU 캐시
비휘발성 (디스크):
- 전원 차단 후에도
- HDD, SSD
- Durability 의 기반
저장 대상:
1. 데이터 파일:
- 실제 데이터
- 변경된 페이지
2. 트랜잭션 로그:
- 변경 이력
- WAL
- 복구용
→ 둘 다 영구 저장소
영구 보존 (ILIC)
ILIC 데이터 영구성:
- 운영 DB (MySQL):
- /var/lib/mysql 디스크
- 트랜잭션 로그
- 데이터 파일
- 서버 다운 시:
- 메모리 사라짐
- 디스크는 그대로
- 재시작:
- 로그 + 데이터 파일로 복구
- commit 된 모든 거래 살아있음
+ 백업 (재해 대비)
+ 복제 (Replication)
"Commit 된 트랜잭션은 영구 보존" 의 의미는?
답:
1. 영구:
vs 휘발성:
저장:
신뢰:
왜 캐시:
매 변경마다 디스크?
- 디스크 느림 (HDD: ms)
- SSD 도 RAM 보다 100배 느림
- 성능 ↓
→ 메모리 캐시 (버퍼 풀)
- 빠른 변경
- 나중에 디스크
버퍼 풀 (InnoDB):
메모리 캐시:
- 데이터 페이지 보관
- 변경 시 메모리에서
- 디스크는 나중
→ 성능 위해 필수
문제:
메모리만 변경:
- 빠름
- 하지만 휘발성!
- 전원 차단 시 사라짐
→ commit 했는데 사라질 수
→ Durability 위반
동기 vs 비동기 디스크 쓰기:
동기 (Sync):
- 매번 디스크 (느림)
- Durability 보장
- 성능 ↓
비동기 (Async):
- 나중에 디스크 (빠름)
- 사이 장애 시 사라짐
- Durability X
→ WAL 로 해결 (다음)
메모리 캐시 문제 (ILIC)
ILIC MySQL InnoDB:
- innodb_buffer_pool_size: 1G ~ 수십 G
- 데이터/인덱스 캐시
쿼리 동작:
UPDATE shipments SET status = 'SHIPPED' WHERE id = 1;
- 1. 버퍼 풀에서 페이지 찾음 (메모리)
- 2. 메모리에서 변경 (빠름)
- 3. 디스크는 나중 (체크포인트)
만약 commit 후 즉시 전원 차단:
- 메모리 변경 사라짐
- 디스크 안 반영
- → Durability 위반?
→ WAL 이 해결 (commit 시 로그 강제 기록)
단순 디스크 저장보다 복잡한 이유 (캐시) 는?
답:
1. 캐시 이유:
버퍼 풀:
문제:
해결:
WAL (Write-Ahead Logging):
"변경 전 로그 먼저":
- 데이터 변경 전에
- 변경 로그를 디스크에 기록
- 데이터 변경은 나중에 (메모리)
→ 로그 = 진실의 원천
WAL 순서:
1. SQL 실행 (변경 의도)
2. 로그에 기록 (디스크) ← 핵심
3. 메모리 (버퍼 풀) 변경
4. (나중) 데이터 파일 디스크 반영
commit 시점:
commit 호출:
1. 로그를 디스크에 강제 (fsync)
2. commit 확정 → 사용자에 응답
데이터 파일:
- 아직 메모리만
- 나중에 (체크포인트)
→ 로그만 디스크면 OK
핵심 아이디어:
"데이터 자체 < 로그":
- 로그만 있으면
- 재시작 시 복구 가능
- 로그 → 데이터 재구성
→ 로그가 진실
WAL (ILIC MySQL InnoDB)
ILIC 의 WAL:
- Redo Log (ib_logfile0/1):
- 변경 로그
- 디스크
- WAL 의 구현
UPDATE shipments SET status = 'SHIPPED' WHERE id = 1;
COMMIT;
내부:
1. 페이지 변경 (메모리)
2. Redo Log 에 변경 기록 (메모리 로그 버퍼)
3. COMMIT 시 Redo Log 디스크 fsync
4. 사용자에 "성공" 응답
5. (나중) 데이터 페이지 디스크 (체크포인트)
만약 직후 다운:
- Redo Log 디스크에 있음
- 재시작 시 Redo 적용
- 데이터 살아있음 (Durability)
트랜잭션 로그 (WAL) 란?
답:
1. WAL:
순서:
commit 시점:
핵심:
fsync (file sync):
OS 시스템 콜:
- 파일 캐시 → 디스크 강제
- "확실히 적힘" 보장
- flush 와 다름
- 디스크 하드웨어까지
왜 필요:
OS 도 캐시:
- 파일 쓰기 → OS 캐시
- 디스크는 나중
- 빠름
fsync:
- OS 캐시 → 디스크 강제
- 정전 시 안전
→ Durability 의 핵심
fsync 비용:
- 디스크 회전 대기 (HDD)
- 또는 SSD 쓰기
- ms 단위
매 commit:
- 한 번 fsync
- 트랜잭션마다 비용
→ ACID 가장 비싼 부분
다중 트랜잭션:
여러 트랜잭션 동시 commit:
- 그룹 커밋 (Group Commit)
- 묶어서 한 fsync
- 처리량 ↑
→ MySQL/InnoDB 최적화
fsync (ILIC)
ILIC commit 시:
1. Redo Log 에 변경 기록 (메모리 로그 버퍼)
2. fsync 호출 → OS 캐시 → 디스크
3. 응답
비용:
- SSD: ~0.5 ms
- HDD: ~5-10 ms
ILIC 같은 트래픽:
- 초당 수백 commit
- fsync 가 병목 가능
→ 그룹 커밋 + SSD 사용
→ 또는 Durability 약화 (다음 섹션)
fsync 의 역할은?
답:
1. fsync:
이유:
비용:
최적화:
복구 절차:
1. DB 재시작
2. Redo Log 읽기
3. 미반영 변경 적용 (Redo)
4. 미커밋 트랜잭션 취소 (Undo)
5. 정상 상태 복원
→ 자동
Redo:
Commit 된 변경 다시 적용:
- Redo Log 보고
- 데이터 파일에 반영
- 사라진 변경 복원
→ Durability 보장
Undo:
미커밋 변경 취소:
- 다운 시 진행 중인 트랜잭션
- Undo Log 보고 복원
- 처음 상태로
→ Atomicity 보장
ARIES 알고리즘:
3단계 복구:
1. Analysis: 무엇이 일어났나
2. Redo: 다시 적용
3. Undo: 미커밋 취소
→ 대부분 DB 가 채택
복구 시나리오 (ILIC)
ILIC 서버 다운:
- 진행 중 트랜잭션 5개
- 그 중 3개 commit, 2개 미커밋
- 갑자기 전원 차단
재시작 시:
1. InnoDB 가 Redo Log 읽음
2. 3개 commit 변경 → Redo (적용)
3. 2개 미커밋 → Undo (취소)
4. 정상 상태
5. 사용자 접근 가능
→ commit 된 거래는 모두 살아있음
→ Durability 보장
→ 약 수 초 ~ 수십 초 복구 시간
시스템 장애 후 복구 동작은?
답:
1. 절차:
Redo:
Undo:
알고리즘:
Redo Log (InnoDB):
순환 로그 파일:
- 변경 이력 기록
- 고정 크기 (재사용)
- ib_logfile0, ib_logfile1
→ WAL 의 구현
체크포인트 (Checkpoint):
주기적으로:
- 메모리 (버퍼 풀) 변경
- 디스크 데이터 파일 반영
- Redo Log 의 그 부분 재사용 가능
→ Redo Log 공간 회수
체크포인트 효과:
- Redo Log 공간 회수 (순환)
- 복구 시간 ↓ (적은 Redo)
- 데이터 파일 최신
→ 균형 (체크포인트 비용)
빈도 트레이드오프:
자주:
- Redo Log 작음
- 복구 빠름
- 디스크 I/O ↑
드물게:
- Redo Log 큼
- 복구 느림
- 디스크 I/O ↓
Redo Log + 체크포인트 (ILIC)
ILIC MySQL InnoDB:
- ib_logfile0/1: 각 100MB 정도 (기본)
- 변경 기록 → 순환
체크포인트:
- 주기적 (Adaptive Flushing)
- 버퍼 풀의 더티 페이지 → 디스크
- Redo Log 공간 회수
설정 (my.cnf):
innodb_log_file_size = 256M # 로그 크기
innodb_log_files_in_group = 2 # 파일 개수
innodb_io_capacity = 1000 # I/O 능력
Redo Log 와 체크포인트는?
답:
1. Redo Log:
체크포인트:
효과:
트레이드오프:
가장 비싼 이유:
매 commit 마다:
- fsync (디스크 I/O)
- ms 단위 비용
- 다른 작업 대기
→ 누적 비용 ↑
다른 성질 비교:
Atomicity:
- undo log (메모리 위주)
Consistency:
- 제약 검증 (메모리 위주)
Isolation:
- 락 (메모리 위주)
Durability:
- fsync (디스크 강제!) ← 가장 비쌈
처리량 영향:
fsync 가 병목:
- 디스크 I/O 느림
- 초당 트랜잭션 수 제한
- HDD: ~수백 TPS
- SSD: ~수천 TPS
→ Durability 가 처리량 제한
완화 방법:
- 그룹 커밋 (여러 commit 묶음)
- SSD/NVMe
- 배터리 백업 RAID
- innodb_flush_log 조정
- 비동기 commit (위험)
가장 비싼 (ILIC)
ILIC 트랜잭션 처리:
- 매 commit fsync
- 디스크 I/O 병목
ILIC SSD 운영:
- 초당 ~1000+ TPS 가능
최적화:
- innodb_flush_log_at_trx_commit 조정
- 그룹 커밋
- 복제 (replication, 비동기)
→ Durability 가 가장 비싸지만
→ 가장 중요 (사라지면 사고)
ACID 중 가장 비싼 성질인 이유는?
답:
1. 이유:
비교:
처리량:
완화:
innodb_flush_log_at_trx_commit:
MySQL InnoDB 핵심 설정:
- 0: 1초마다 fsync (위험, 빠름)
- 1: 매 commit fsync (안전, 느림) ← 기본
- 2: 매 commit OS 캐시, 1초마다 fsync (절충)
| 값 | 안전성 | 성능 | 손실 |
|---|---|---|---|
| 0 | 낮음 | 빠름 | ~1초 (장애 시) |
| 1 (기본) | 완벽 | 느림 | 없음 |
| 2 | 중간 | 빠름 | OS 크래시 시 ~1초 |
sync_binlog (MySQL):
바이너리 로그 동기:
- 복제용 로그
- 0: 안 함, 1: 매번 (안전)
- innodb_flush 와 함께
→ 복제 안전성
실용적 선택:
강한 일관성 (금융/B2B):
- innodb_flush_log_at_trx_commit = 1
- sync_binlog = 1
- 가장 안전
일반 (성능 우선):
- = 2 (OS 캐시까지만 강제)
- 또는 그룹 커밋
→ 비즈니스 따라
ILIC 설정 (my.cnf)
ILIC 가 B2B 물류:
- 데이터 손실 절대 X
- innodb_flush_log_at_trx_commit = 1
- sync_binlog = 1
성능 보완:
- SSD/NVMe
- 충분한 RAM (버퍼 풀)
- 그룹 커밋 활용
- 복제 (replica)
주의:
- 결제/정산 트랜잭션은 절대 안 약화
- 통계 등은 약간 약화 가능
| Q | 핵심 답변 |
|---|---|
| Durability? | commit 영구 |
| 영구 보존? | 장애 후도 |
| 캐시 문제? | 휘발성 |
| WAL? | 변경 전 로그 |
| fsync? | OS → 디스크 강제 |
| 복구? | Redo + Undo |
| 체크포인트? | 메모리 → 디스크 |
| 가장 비싼? | fsync I/O |
| MySQL 설정? | innodb_flush_log |
| 그룹 커밋? | 묶음 fsync |
답:
답:
답:
답:
답:
1. Durability (지속성)
2. WAL + fsync
3. ACID 중 가장 비싼
innodb_flush_log_at_trx_commit 으로 트레이드오프 조정이번 Unit에서 Durability 를 봤다면, 다음은 Commit 이전 동시성 (★ 깊이 파기, Phase 6 마지막).
💎 Phase 6 — 트랜잭션과 ACID
✅ Unit 6.1 트랜잭션이란
✅ Unit 6.2 Atomicity ★깊이
✅ Unit 6.3 Consistency ★깊이
✅ Unit 6.4 Isolation ★깊이
✅ Unit 6.5 Durability ★깊이 ← 여기
⏭ Unit 6.6 Commit 이전 동시성 ★깊이 — Phase 6 완주
🧪 Part A (9 Unit) ✅
💾 Part B — DB 접근의 진화
✅ Phase 3 — JDBC (3)
✅ Phase 4 — Connection Pool (4)
✅ Phase 5 — DataSource (4)
💎 Phase 6 — ACID (5/6)
총: 25/28 Unit (89%!)
★ 깊이 파기 — Durability 완료