[MySQL] MVCC(Multi Version Concurrency Control)란
학습해야 하는 이유
- MVCC를 이해해야 트랜잭션 격리 수준에 따른 MySQL 내부 동작 원리에 대해서 알 수 있기 때문입니다.
- MVCC를 이해하기 위해선, Undo Log에 대해 알아야 합니다. 또 Undo Log와 헷갈릴 수 있는 Redo Log에 대해서도 알아봅시다. Redo Log와 Undo Log는 MySQL 스토리지 엔진 내에 존재하는 데이터 영역입니다.
Redo Log
정의
- DDL 또는 DML 문장에 의해 데이터베이스에 저장된 값 또는 테이더베이스 구조에 변경사항이 생기는 경우 변경 정보를 보관하는 메모리 영역입니다.
Redo Log가 필요한 이유
- 기본적으로 DB에서 데이터 변경 작업은 부하가 큰 작업입니다. 많은 경우 변경 대상인 데이터가 순차적으로 위치하지 않고 디스크에 랜덤하게 존재하기 때문입니다. 그래서 이러한 부하를 줄이기 위해, MySQL에선 스토리지 엔진에 변경된 데이터를 버퍼링해 두기 위해
InnoDB 버퍼 풀
과 같은 장치를 둡니다. - 하지만 이 장치만으로는 트랜잭션의 ACID를 보장할 수 없기 때문에, 변경된 내용을 순차적으로 디스크에 기록하는 로그 파일을 두는데, 이를 Redo Log(리두 로그)라고 합니다. 즉, 더 나은 성능을 위해 필요합니다.
- 트랜잭션이 커밋되는 순간 LGWR(Log Writer)에 의해 리두 로그 파일(Redo Log file)로 저장되는데, 메모리 영역에 저장된 데이터를 디스크에 쓴다고 보면 됩니다.
Undo Log (실행 취소 로그)
정의와 특징
- UPDATE 문이나 DELETE 문으로 데이터를 변경했을 때 변경되기 전의 데이터(이전 데이터)를 보관하는 곳 입니다.
- 언두 로그는 2가지 용도로 사용됩니다. 첫 번째는 트랜잭션의 롤백 대비 용도입니다. 트랜잭션 롤백 시, 변경되기 이전 데이터로 돌려야하기 때문에 이전 데이터를 보관하고 있어야 합니다. 두 번째는 트랜잭션의 격리 수준을 유지하면서 높은 동시성을 제공하는 데 사용됩니다. 이 부분이 조금 어려운데요, 트랜잭션 격리 수준 중 Repeatable Read에서 MVCC를 지키기 위해 언두 영역에 백업된 이전 데이터를 이용해, 동일 트랜잭션 내에서는 동일한 결과를 보여줄 수 있도록 보장합니다. 하나의 트랜잭션이 끝나기 전까지는 Undo Log에 저장된 데이터를 불러오는 방식으로 말이죠.
MVCC(Multi Version Concurrency Control)
아마 위 설명이 완벽하게 이해되시지 않을 것입니다. 이를 이해하려면 위에서 앞서 언급된 MVCC에 대해서 알아야 하는데요.
정의
- MVCC란 하나의 레코드에 대해 다양한 버전을 동시에 관리하는 기술입니다. 이를 보장하는 이유는 트랜잭션 격리 수준에 따른 결과값이 서로 다르기 때문입니다.
- 자세한 설명을 위해, 예를 들어보겠습니다. id, name, hobby로 구성된 User 테이블이 있다고 해봅시다. id가 1이고 name이 김종국, hobby가 운동인 값이 있습니다. 이를 아래 SQL 문을 실행하고 동시에 조회 쿼리를 실행하면 commit 이전이라고 가정했을 때, 어떤 결과가 나올까요?
UPDATE User SET hobby = '춤' WHERE id = 1 ;
SELECT * FROM User WHERE id = 1;
- 이는 트랜잭션 격리 수준에 따라 다릅니다. 커밋 이전 데이터를 조회하는 트랜잭션 격리 수준인
READ_UNCOMMITED
에서는 변경 후 데이터인 '춤'이 조회되고, 그 외 그보다 더 높은 격리 수준에서는READ_COMMITED, REPEATABLE_READ, SERIALAZABLE
에선 변경 전 데이터인 '운동'이 조회됩니다. - 이는 메모리 내부적으로 InnoDB 버퍼풀에는
춤
을, 언두 로그에서는운동
을 보관하고 있는데, 이는READ_UNCOMMITED
에서는 커밋 이전의 데이터도 조회되기 때문이고 그보다 높은 수준에서는 커밋 이후 데이터를 조회하기 때문입니다.
추가질문
Q. Repeatable Read Isolation 레벨에서는 해당 분리 레벨을 보장하기 위해 실행 취소 로그의 데이터 값이 검색됩니다. 여기서, 실행 취소 로그 중에서 어떤 버전의 데이터를 읽을 것인지 결정하는 방법은 무엇일까요?
A. MySQL 문서에 따르면, InnoDB는 Repeatable Read 수준에서 Undo 로그의 정보를 사용하여 일관된 읽기를 위해 수정된 행의 이전 버전을 구성합니다. InnoDB는 어떤 버전의 데이터를 읽을지 결정하기 위해 MVCC(Multi-version Concurrency Control)라는 메커니즘을 사용하는데, 이 메커니즘은 트랜잭션 ID라고 불리는 고유 식별자를 각 트랜잭션에 할당합니다. 테이블의 각 행에는 행을 삽입하거나 삭제한 마지막 트랜잭션의 트랜잭션 ID를 저장하는 두 개의 숨겨진 열과 업데이트를 위한 실행 취소 로그 레코드에 대한 포인터도 있습니다. 이 열을 각각 DB_TRX_ID 및 DB_ROLL_PTR이라고 합니다.
마무리
오늘은 간단하게 MVCC와 Undo Log, Redo Log에 대해서 알아보았습니다. 다음 시간에는 이 내용보다 더 근본이 되는 MySQL 아키텍처(MySQL 엔진, 스토리지 엔진)에 대해서 알아보겠습니다. 시간이 되면, MySQL 내 트랜잭션 격리 수준에 대해서도 알아보겠습니다.
참고 자료
Real MySQL 8.0
[10분 테크톡] 우기의 MySQL 아키텍처