본문으로 건너뛰기

InnoDB는 왜 Redo한 뒤 Undo하는가

Redo는 커밋된 변경을 살리고 Undo는 미커밋 변경을 지운다고만 구분하면 Crash Recovery의 순서가 잘 설명되지 않습니다. InnoDB는 먼저 Redo를 적용하고, 그 뒤에 미완료 트랜잭션을 Undo합니다.

SQL Transaction이 끝나기 전에도 UPDATE 과정에서 Redo가 만들어지고, Background Log Flush나 WAL 조건에 따라 파일까지 영속화될 수 있습니다. Redo 안에 COMMIT된 변경만 들어 있다고 볼 수 없는 이유입니다.

장애 시점은 COMMIT 호출보다 내구성 경계로 나눈다

아래 표는 Binary Log를 사용하지 않는 단일 InnoDB 트랜잭션의 내부 경로만 다룹니다. Binary Log가 켜져 있으면 MySQL Server의 2PC와 sync_binlog까지 함께 봐야 합니다. 여기서는 일반 영구 테이블 UPDATE와 innodb_flush_log_at_trx_commit=1을 기준으로 COMMIT 전후 장애를 나눠 보겠습니다.

장애 시점서버가 복원할 수 있는 결과클라이언트가 아는 것
COMMIT 요청 뒤, 목표 LSN의 durable flush 완료를 확인하기 전BOOKED 또는 CANCELLED가 될 수 있습니다. COMMIT 관련 Redo가 장애 전에 어디까지 영속화됐는지에 따라 달라집니다.성공 여부를 알 수 없습니다.
목표 LSN까지 flush된 뒤, 응답 전COMMIT 상태를 복원할 Redo가 남아 있으므로 CANCELLED가 돼야 합니다.성공 응답을 받지 못했으므로 결과가 불확실합니다.
COMMIT 성공 응답 뒤정상 저장 계층을 전제로 CANCELLED가 돼야 합니다.성공을 확인했습니다.

응답 전에 연결이 끊겼다면 애플리케이션은 COMMIT 여부를 단정할 수 없습니다. 결과를 조회하거나 중복 실행을 막을 기준이 필요합니다. 이 문제는 InnoDB 내부 복구와 별개로 애플리케이션에서 처리해야 합니다.

Recovery는 Page 상태를 먼저 복원한다

InnoDB Recovery의 주요 순서는 다음과 같습니다.

text
Tablespace Discovery

Redo Log Application

Rollback of Incomplete Transactions

Redo Log Application은 서버가 연결을 받기 전에 수행됩니다. 이후 미완료 트랜잭션의 Rollback은 백그라운드에서 새 작업과 병행될 수 있으며, 끝날 때까지 잠금 충돌이 생길 수 있습니다.

InnoDB는 Redo가 가리키는 Tablespace를 찾고 최신 Checkpoint 이후의 유효한 Redo를 읽습니다. 이어 Data/Index Page와 Undo 관련 Page에 필요한 변경을 적용합니다.

Checkpoint 이후 완결된 Redo Group을 확인하고 Page에 적용하는 과정

Redo Application은 커밋된 SQL만 골라 다시 실행하는 과정이 아닙니다. 이 글의 UPDATE 예시에서는 영속 Redo의 완결된 기록을 읽고, 필요한 Data/Index Page와 Undo Page 변경을 복원합니다.

Checkpoint가 Redo Group의 중간을 가리킬 수 있으므로 실제 Recovery는 Mini-Transaction Group의 경계도 확인합니다. 완결되지 않은 Group을 절반만 적용하지 않기 위해서입니다. Page가 이미 더 최신이라면 같은 변경을 다시 적용할 필요도 없습니다.

커밋하지 않은 변경도 Redo 대상이 될 수 있다

첫 번째 COMMIT으로 CANCELLED가 된 뒤 다음 UPDATE를 실행했다고 해보겠습니다.

sql
START TRANSACTION;

UPDATE reservations
SET status = 'REFUNDING'
WHERE id = 1;

-- COMMIT하지 않은 상태에서 장애 발생

COMMIT하지 않은 UPDATE의 Redo도 Log File에 기록될 수 있습니다. 미완료 변경이 들어간 Page를 파일에 쓰려면 WAL 조건에 따라 관련 Redo가 먼저 영속화돼야 하고, Background Log Flush가 그보다 앞서 진행될 수도 있습니다.

따라서 Recovery가 읽는 Redo에는 커밋한 CANCELLED와 미완료 REFUNDING의 변경이 함께 들어 있을 수 있습니다. 미커밋 변경을 처음부터 제외할 수 없는 이유는 Undo Page와 Transaction 상태도 유효한 지점까지 복원해야 하기 때문입니다.

Redo 단계에서는 Page의 물리 상태를 먼저 복원합니다. 어떤 변경을 최종적으로 남길지는 다음 Undo 단계에서 결정합니다.

Undo하려면 Undo 정보도 먼저 복원해야 한다

Undo Log는 InnoDB가 관리하는 영속 Page에 저장됩니다. 일반 영구 테이블의 Undo Page와 Rollback Segment 관련 변경도 Redo의 보호를 받습니다.

Redo를 적용한 뒤 InnoDB는 Rollback Segment와 Undo Log Header를 읽어 장애 전에 존재하던 Transaction을 다시 구성합니다.

Redo 적용 뒤 Undo 메타데이터로 완료된 트랜잭션과 ACTIVE, XA PREPARED를 나누는 과정

text
Redo Application 완료

Rollback Segment와 Undo Log 확인
├─ 완료된 UPDATE Undo → History List와 Purge 대상
├─ 일반 ACTIVE Transaction → 자동 Rollback
└─ 외부 XA PREPARED → XA RECOVER 후 COMMIT/ROLLBACK 결정 대기

COMMIT된 UPDATE의 Undo가 곧바로 사라지는 것은 아닙니다. 이전 버전을 읽는 Transaction이 있을 수 있으므로 History List에 남았다가 더는 필요하지 않을 때 Purge됩니다.

장애 당시 끝나지 않은 일반 Transaction은 Undo Records를 역방향으로 따라 Rollback합니다. 이번 예시에서는 REFUNDING이 사라지고 마지막 COMMIT 값인 CANCELLED가 남습니다.

Data Page와 Transaction 상태를 따로 본다

BOOKED → CANCELLED는 COMMIT했고, CANCELLED → REFUNDING은 COMMIT하지 않은 채 장애가 났다고 가정하겠습니다.

Transaction 상태Data File의 값복구 과정최종 값
CANCELLED까지 COMMITTEDBOOKED필요한 Redo로 CANCELLED를 복원합니다.CANCELLED
CANCELLED까지 COMMITTEDCANCELLED이미 반영된 오래된 Redo를 건너뜁니다.CANCELLED
REFUNDING이 ACTIVECANCELLED필요한 Page와 Undo 정보를 복원한 뒤 Rollback합니다.CANCELLED
REFUNDING이 ACTIVEREFUNDING먼저 저장된 미완료 변경을 Undo합니다.CANCELLED

Recovery는 Data File에 남은 Page LSN을 기준으로 이미 반영된 변경은 건너뛰고 필요한 Redo를 적용합니다. 최종 논리 상태는 복원된 Transaction 상태와 Undo 처리가 결정합니다.

다만 외부 XA 트랜잭션이 XA PREPARE까지 끝난 상태라면 일반 ACTIVE 트랜잭션처럼 자동 Rollback하지 않습니다. 재시작 뒤 XA RECOVER로 확인한 다음 Transaction Manager가 XA COMMIT 또는 XA ROLLBACK을 내려야 끝납니다.