Doublewrite Buffer — 부분 쓰기 방지와 데이터 무결성
디스크에 16KB 데이터를 쓰는 도중 전원이 나가면 어떻게 될까요? 절반만 기록된 데이터를 복구할 수 있을까요?
Partial Write 문제
InnoDB는 16KB 크기의 페이지 를 기본 단위로 사용합니다. 하지만 대부분의 운영체제와 디스크는 4KB 단위(섹터) 로 데이터를 기록합니다.
InnoDB 페이지 (16KB)
┌──────┬──────┬──────┬──────┐
│ 4KB │ 4KB │ 4KB │ 4KB │
│ ① │ ② │ ③ │ ④ │
└──────┴──────┴──────┴──────┘
OS가 디스크에 기록하는 단위: 4KB씩 4번
16KB 페이지를 디스크에 쓸 때 OS는 4KB씩 4번에 나눠 기록합니다. 만약 2번째 4KB를 기록하는 도중 서버가 비정상 종료되면 어떻게 될까요?
정상 기록 전: [구 데이터 16KB 전체]
장애 발생 후: [새 4KB ①] [새 4KB ② 일부] [구 4KB ③] [구 4KB ④]
↑ 새 데이터 ↑ 손상 ↑ 구 데이터
이 상태의 페이지는 완전히 망가진 상태입니다. 새 데이터도 구 데이터도 아닌, 사용할 수 없는 상태가 됩니다.
Redo Log만으로는 복구할 수 없는 이유
"Redo Log가 있으니 복구할 수 있지 않나요?"라고 생각할 수 있습니다. 하지만 Redo Log는 정상적인 페이지에 변경을 재적용 하는 것입니다.
Redo Log: "페이지 X의 offset 100 위치에 값 42를 기록"
이 로그를 적용하려면 페이지 X가 올바른 상태여야 합니다. 부분적으로 기록된 손상 페이지에 Redo Log를 적용하면 데이터가 더 망가집니다.
Doublewrite Buffer란
Doublewrite Buffer는 이 문제를 해결하는 안전장치입니다. 페이지를 데이터 파일에 쓰기 전에 별도의 영역에 먼저 복사 해둡니다.
동작 흐름
1. Dirty Page를 Buffer Pool에서 가져옴
2. Doublewrite 영역에 순차적으로 기록 + fsync (디스크에 확실히 저장)
3. 실제 데이터 파일의 해당 위치에 기록
복구 시나리오:
A) 2단계에서 장애 → 데이터 파일의 기존 페이지가 온전 → Redo Log 적용 가능
B) 3단계에서 장애 → Doublewrite 영역의 복사본으로 페이지 복원 → Redo Log 적용
Buffer Pool
┌─────────┐
│ Dirty │
│ Pages │
└────┬────┘
│
① 먼저 기록
▼
Doublewrite Buffer (순차 기록)
┌─────────────────────────┐
│ Page A │ Page B │ Page C │
└─────────────────────────┘
│
② 그 다음 기록
▼
데이터 파일 (랜덤 위치)
┌──┐ ┌──┐ ┌──┐
│ A│ │ B│ │ C│
└──┘ └──┘ └──┘
복구 과정
서버가 비정상 종료 후 다시 시작되면 InnoDB는 다음을 수행합니다.
- 데이터 파일의 각 페이지 체크섬을 검증합니다
- 체크섬이 맞지 않으면 (Partial Write 발생) Doublewrite 영역에서 정상 복사본을 가져옵니다
- 복원된 페이지에 Redo Log를 적용하여 최신 상태로 만듭니다
복구 흐름:
데이터 파일 페이지 검증
├─ 체크섬 OK → Redo Log 적용
└─ 체크섬 FAIL → Doublewrite에서 복원 → Redo Log 적용
성능 영향
Doublewrite는 모든 페이지를 두 번 쓰기 때문에 "쓰기 양이 2배"로 보일 수 있습니다. 하지만 실제 성능 영향은 그보다 작습니다.
왜 2배보다 적은가
- **순차 쓰기 **: Doublewrite 영역에는 여러 페이지를 모아서 순차적으로 기록합니다. 순차 I/O는 랜덤 I/O보다 훨씬 빠릅니다
- ** 배치 처리 **: 한 번의 fsync로 여러 페이지를 함께 기록합니다
- ** 실제 오버헤드 **: 일반적으로 5~10% 정도의 쓰기 성능 감소
SSD에서의 영향
SSD에서는 상황이 조금 다릅니다.
- SSD는 순차/랜덤 I/O 성능 차이가 적습니다
- 하지만 SSD의 쓰기 수명(Write Endurance)에 영향을 줍니다
- Doublewrite로 인한 추가 쓰기가 SSD 수명을 단축시킬 수 있습니다
MySQL 8.0에서의 변경사항
8.0.20 이전
Doublewrite 영역이 ** 시스템 테이블스페이스(ibdata1)** 안에 있었습니다.
ibdata1
├─ 시스템 테이블스페이스 데이터
├─ Doublewrite Buffer (2MB, 128페이지)
└─ 기타 시스템 정보
8.0.20 이후
별도의 Doublewrite 파일 로 분리되었습니다.
#ib_16384_0.dblwr -- Doublewrite 파일 1
#ib_16384_1.dblwr -- Doublewrite 파일 2
분리의 장점은 다음과 같습니다.
- Doublewrite 파일을 별도 디스크에 배치 가능 (I/O 분산)
- 시스템 테이블스페이스 크기 감소
- 병렬 Doublewrite 가능 (여러 Buffer Pool 인스턴스가 각자의 Doublewrite 파일 사용)
관련 설정
-- Doublewrite 활성화 여부 (기본 ON)
SHOW VARIABLES LIKE 'innodb_doublewrite';
-- Doublewrite 파일 경로 (8.0.20+)
SHOW VARIABLES LIKE 'innodb_doublewrite_dir';
-- Doublewrite 파일 수 (8.0.20+)
SHOW VARIABLES LIKE 'innodb_doublewrite_files';
-- 페이지당 Doublewrite 배치 크기 (8.0.20+)
SHOW VARIABLES LIKE 'innodb_doublewrite_batch_size';
Doublewrite 비활성화를 고려하는 경우
비활성화가 안전한 상황
-
**원자적 쓰기를 지원하는 파일시스템 **: ZFS, FusionIO 등 파일시스템 레벨에서 원자적 쓰기를 보장하면 Partial Write가 발생하지 않습니다
-
** 원자적 쓰기를 지원하는 스토리지 **: 일부 하드웨어가 16KB 원자적 쓰기를 지원합니다
-- 비활성화
SET GLOBAL innodb_doublewrite = OFF;
-- 또는 my.cnf에서 설정
-- [mysqld]
-- innodb_doublewrite = 0
비활성화가 위험한 상황
- 일반 ext4, XFS 파일시스템 사용 시
- 전원 장애가 발생할 수 있는 환경
- 데이터 손실이 허용되지 않는 운영 환경
Doublewrite vs Redo Log vs Undo Log
세 가지가 각각 다른 목적을 가지고 있습니다.
| 구분 | 목적 | 보호 대상 |
|---|---|---|
| Doublewrite | Partial Write 방지 | 페이지의 물리적 무결성 |
| Redo Log | 커밋된 변경 복구 (Durability) | 트랜잭션의 논리적 무결성 |
| Undo Log | 롤백, MVCC | 트랜잭션 취소, 읽기 일관성 |
장애 복구 흐름:
1. Doublewrite로 손상된 페이지 복원 (물리적 복구)
2. Redo Log로 커밋된 트랜잭션 재적용 (논리적 복구)
3. Undo Log로 미커밋 트랜잭션 롤백 (일관성 복구)
모니터링
-- Doublewrite 통계
SHOW STATUS LIKE 'Innodb_dblwr%';
| 변수 | 설명 |
|---|---|
| Innodb_dblwr_pages_written | Doublewrite에 기록된 총 페이지 수 |
| Innodb_dblwr_writes | Doublewrite 영역에 기록한 횟수 |
-- 배치당 평균 페이지 수 계산
SELECT
Innodb_dblwr_pages_written / Innodb_dblwr_writes AS pages_per_write
FROM (
SELECT
(SELECT VARIABLE_VALUE FROM performance_schema.global_status
WHERE VARIABLE_NAME = 'Innodb_dblwr_pages_written') AS Innodb_dblwr_pages_written,
(SELECT VARIABLE_VALUE FROM performance_schema.global_status
WHERE VARIABLE_NAME = 'Innodb_dblwr_writes') AS Innodb_dblwr_writes
) t;
이 값이 1에 가까우면 페이지가 하나씩 기록되고 있다는 의미이고, 값이 높을수록 효율적인 배치 처리가 이루어지고 있다는 의미입니다.
주의할 점
Redo Log만으로는 Partial Write를 복구할 수 없다
Redo Log는 "정상 페이지에 변경을 재적용"하는 것입니다. 절반만 기록된 손상 페이지에 Redo Log를 적용하면 데이터가 더 망가집니다. Doublewrite Buffer가 정상 페이지 복사본을 제공하는 이유입니다.
일반 파일시스템(ext4, XFS)에서 비활성화하면 데이터가 손상될 수 있다
원자적 쓰기를 보장하지 않는 파일시스템에서 Doublewrite를 끄면, 전원 장애 시 복구 불가능한 페이지 손상이 발생합니다. ZFS나 특수 하드웨어에서만 비활성화를 검토해야 합니다.
SSD에서는 쓰기 수명에 영향을 준다
Doublewrite로 인한 추가 쓰기가 SSD의 Write Endurance를 단축시킵니다. 다만 데이터 무결성과의 트레이드오프이므로, 안전성을 우선하는 것이 일반적입니다.
정리
| 항목 | 설명 |
|---|---|
| 문제 | 16KB 페이지를 4KB 단위로 쓰는 중 장애 시 Partial Write |
| 해결 | Doublewrite 영역에 먼저 순차 기록 → 데이터 파일에 기록 |
| 복구 | 체크섬 실패 시 Doublewrite에서 복원 → Redo Log 적용 |
| 성능 영향 | 순차 쓰기이므로 실제 오버헤드 5~10% |
| 8.0.20 변경 | 시스템 테이블스페이스에서 별도 .dblwr 파일로 분리 |
| 비활성화 | ZFS 등 원자적 쓰기 보장 파일시스템에서만 안전 |