InnoDB의 트랜잭션 처리 및 그에 따른 Redo 로그와 Undo 정보 및 MVCC의 구현을
간단한 테이블과 업데이트 문장을 통해서 살펴보고자 한다.
CREATE TABLE user (
userid varchar(10) not null,
name varchar(20) not null,
area varchar(100) not null,
PRIMARY KEY (userid),
INDEX ix_area (area)
);
INSERT INTO user(userid, name, area) VALUES ('brew','이성욱','서울');
위와 같은 데이터를 가진 테이블을 가정하고,
해당 데이터를 UPDATE하는 시나리오를 통해서 트랜잭션 및 로그(Undo/Redo)의 발생 및
체크 포인트 발생시 디스크에 저장되는 방식을 알아보자.
1. 트랜잭션 시작
- Begin; (또는 Start transaction; )
- UPDATE user SET area='경기' where userid='brew';
- 대략(100% 정확치 않음) 아래와 같은 절차로 변경이 적용됨
- [1] 변경되는 컬럼의 이전 값을 저장하는 Undo 로그 레코드 생성 -> 이때 생성되는 Undo 레코드에는 실제 변경되는 컬럼의 이전 값과 PK값만 저장됨
- [2] 버퍼 풀 데이터 페이지의 변경 대상 레코드의 메타 정보중에서 Roll-Pointer 값을 [1]에서 생성된 Undo 로그의 주소값으로 저장
- [3] 버퍼 풀 데이터 페이지의 변경 대상 레코드의 컬럼값을 새로운 값으로 변경하고, 변경되는 컬럼의 이후 값과 데이터 페이지의 주소 및 Offset을 Redo 로그에 저장
- [4] 변경되는 컬럼을 이용한 인덱스가 있으므로, 인덱스의 값을 변경 -> 물론, 해당 인덱스 페이지가 버퍼 풀에 없으면 Insert Buffer에 임시 저장
-> 인덱스 페이지는 단순히 기존 인덱스 키를 덮어쓰기 하는 것이 아니라, 기존 인덱스 키는 그대로 보존하고, 새로운 키 값을 추가함
-> 인덱스 키 하나는 트랜잭션 가시성에 관계없이 모든 값들을 다 가지고 있게 됨
(예를 들어서 키값 "서울"은 다른 값에서 "서울"로 바뀐 레코드뿐만 아니라 "서울"에서 다른 값으로 변경된 레코드의 포인터까지 모두 가지고 있어야 함) - [5] Redo 로그는 "innodb_flush_log_at_trx_commit" 변수 값에 따라서 Semi-Synchronous하게 디스크의 로그 파일로 기록됨
-> 자세한 내용은 매뉴얼의 "Server System Variables" 참조
Redo 로그의 Dirty 페이지(변경된 페이지)가 디스크에 기록되기 전에, 이 Dirty 페이지를 만든 LSN보다 이전에 발생한 LSN의 Redo 로그는 반드시 먼저 디스크에 기록되어야 한다.
-> 더 자세한 내은 "WAL (Write Ahead Log)"로 웹 검색
- 체크포인트로 인해서 디스크에 기록되는 데이터가 모두 Commit된 데이터는 아닐 수 있음
- [6] 체크포인트가 발생하면, InnoDB는 버퍼 풀의 Dirty 페이지(변경된 페이지)들을 디스크에 저장해야 되는데,
이때 디스크에 기록하려고 하는 Dirty 페이지를 변경시킨 LSN과 연관을 가진 모든 Undo 로그를 먼저 디스크에 저장해야 한다.
-> Undo 로그가 디스크에 기록되어 있지 않으면, 현재 디스크로 저장되는 페이지를 Rollback할수 없게 됨 - [7] 변경된 인덱스 페이지와 데이터 페이지를 최종적으로 디스크로 기록
이와 같은 과정을 통해서,
- 랜덤 I/O인 데이터 페이지와 인덱스 페이지의 디스크 기록을 지연시키거나 순차적 I/O로 병합하여 효율적인 쓰기로 개선하게 되며,
- 순차적 I/O인 Redo 로그의 기록도 "innodb_flush_log_at_trx_commit" 변수를 통해서 더 효율적으로 디스크 쓰기로 유도하며,
- Undo 로그를 이용한 Non-Locking consistent read 를 포함한 MVCC를 가능토록 하며,
- MySQL 서버나 장비의 장애에 대해서도 (디스크에 저장된 Redo 로그까지는 복구가 가능토록 하여) 최소한의 데이터 손실만 발생하도록 유도하게 된다.
댓글 없음:
댓글 쓰기