MySQL InnoDB를 공부하다 보면 MVCC(Multi-Version Concurrency)와 이를 통한 잠금 없는 일관성 읽기(Non-locking Consistent Read)라는 개념을 만나게 된다.
책이나 강의에서는 이러한 동시성 제어가 완벽하게 작동하는 비결이 바로 리두 로그(Redo Log), 언두 로그(Undo Log) 덕분이라고 한다. 그렇다면 실제 이 로그 파일들은 어떤 식으로 기록되어 있는 걸까? 궁금증이 생겨서 해당 파일을 직접 열어보았다.
Redo Log, Undo Log, 그리고 MVCC
그 전에 개념을 간단히 정리해보자.
1. Redo Log: "변경사항"을 기록
영속성을 위해 존재하며, 시스템 크래시 발생 시 미처 디스크에 기록되지 못하고 날아간 변경사항을 재실행(redo)하여 데이터를 복구한다.
InnoDB는 성능을 위해 데이터 변경 즉시 디스크의 데이터 파일에 반영하지 않고, 버퍼 풀이라는 메모리 영역에서 먼저 처리한다. 디스크 데이터 파일에 실제로 반영하기 전에 무엇을 바꿀 것인지를 먼저 리두 로그에 기록하고, 그 기록이 디스크에 안전하게 써진 뒤에야 커밋을 완료 처리한다.
2. Undo Log: "변경 이전 데이터"을 기록
일관성을 위해 존재하며, 어떤 row를 변경하기 전에 변경 이전의 값을 기록한다.
1. 롤백: 트랜잭션이 중간에 ROLLBACK 되면, 언두 로그에 남아있는 이전 값으로 데이터를 되돌린다.
2. MVCC / 잠금 없는 일관성 읽기: 격리 수준에 따라 특정 트랜잭션이 과거 버전의 데이터를 안전하게 읽을 수 있도록 돕는다.
3. MVCC와 잠금 없는 일관된 읽기
전형적인 DBMS는 누군가 데이터를 수정 중이면 데이터가 꼬이는 것을 막기 위해 락(Lock)을 걸어 다른 사람의 읽기마저 막아버린다.
InnoDB는 수정이 일어나는 즉시 변경 전 과거 데이터를 언두 로그 영역에 백업해 둔다. 덕분에 다른 트랜잭션은 락에 걸려 대기할 필요 없이, 언두 로그에 보관된 과거 버전을 즉시 읽어간다. 이를 MVCC(다중 버전 동시성 제어)라고 부르며, 덕분에 읽기와 쓰기가 서로를 방해하지 않는 '잠금 없는 일관된 읽기'가 가능해 진다.
실제로 Redo Log를 열어보자
1. 격리 환경 세팅
변경사항을 확실히 확인하기 위해서는, 자동 커밋 옵션을 꺼야 한다.
SELECT @@autocommit;
SET autocommit = 0; --autocommit OFF로 세팅
2. 데이터 변경
테스트를 위해 유저의 닉네임을 변경하는 UPDATE 쿼리를 실행했다. (COMMIT은 아직 실행하지 않음)
UPDATE users
SET nickname = 'chococo'
WHERE userid = 1;
3. 리두 로그 파일 확인하기
$ SHOW VARIABLES LIKE 'datadir'; # 로그 파일 위치 확인
$ ls -la $DATADIR/\#innodb_redo/ # #이 있어서 앞에 \를 붙여줘야 한다
#ib_redo0 #ib_redo1 ...
$ xxd '#ib_redo0' | less # 파일 열어보기
기대했던 파일의 형태는 다음과 같았다.
nickname: 'choco' -> 'chococo'
하지만 실제 파일 내용은 다음과 같이, 바이트 덩어리와 의미를 파악할 수 없는 문자열로 되어 있었다.

다만 페이지 번호와 그 페이지 안의 정확한 위치인 오프셋을 기준으로 기록되어 있는 것까지는 확인할 수 있었다.
왜 사람이 읽을 수 없는 형태로 되어 있을까?
생각해보니 어쩌면 당연한 이유였다. 리두 로그와 언두 로그는 사람이 읽고 디버깅하라고 만든 파일이 아니라, 엔진이 읽고 디스크를 복구하라고 만든 파일이었기 때문이다. 사람 친화적인 파일로 작성했다면, 해당 내용을 다시 파싱하고 해석하느라 추가적인 리소스가 들었을 것이다.
따라서 오직 성능만을 위해 물리적인 디스크 주소와 16진수 바이너리(Hex) 데이터로만 구성되어 있는 이진 포맷으로 되어 있다.
그럼 이전 기록들을 확인할 수 있는 방법은 없을까?
1. 트랜잭션/락/undo 사용량 확인할 때
SHOW ENGINE INNODB STATUS;
트랜잭션이 커밋되지 않고 살아있는 동안, 엔진 상태 창을 켜면 수치화된 통계 수치로 확인할 수 있다.
- 현재 진행 중인 트랜잭션 목록
- 각 트랜잭션이 유지하고 있는 undo 레코드 수
- 락 대기 상황
등을 확인할 수 있다.
2. BINARY LOG 파싱
리두 로그가 아닌 바이너리 로그를 확인해야 한다.
# 터미널에서 바이너리 로그 파싱 명령어 실행
mysqlbinlog -v --base64-output=DECODE-ROWS /var/lib/mysql/binlog.000001
결론
Redo Log, Undo Log 파일에는 어떤 내용을 기록하는지에 대한 궁금증으로 시작된 포스팅이었는데, 사실은 해당 내용은 사람에게는 크게유용한 정보는 아니며 굳이 볼 필요성도 없다는 것을 깨닫게 되었다. 단순한 결론을 미처 생각하지 못했다는 것이 좀 아쉽긴 하지만, 어떤 상황에서 컴퓨팅 친화적 설계가 필요한지에 대해 생각해볼 수 있었던 것 같다.
'Backend > Database' 카테고리의 다른 글
| [MySQL] MySQL 성능 모니터링 방법 (0) | 2024.04.04 |
|---|---|
| [MySQL] 데이터베이스 확장 방식 (0) | 2024.03.21 |
| [MySQL] 커서(Cursor) (0) | 2024.03.14 |
| [MySQL] Direct I/O (0) | 2024.02.29 |
| [MySQL] 문자열 패턴 매칭 연산자 (REGEXP, LIKE) (2) | 2024.02.22 |