언두 로그
InnoDB 스토리지 엔진은 트랜잭션과 격리수준을 보장하기 위해 DML(INSERT, UPDATE, DELETE)로 변경되기 이전 버전의 데이터를 별도로 백업한다. 백업된 데이터를 언두로그(Undo Log)라 한다. 언두로그가 어떻게 사용되는지 간단히 살펴보자.
트랜잭션 보장
트랜잭션이 롤백되면 트랜잭션 도중 변경된 데이터를 변경 전 데이터로 복구해야 한다. 이때 언두 로그를 사용한다.
격리 수준 보장
특정 커넥션에서 데이터를 변경하는 도중 다른 커넥션에서 데이터를 조회하면 트랜잭션 격리 수준에 맞게 변경 중인 레코드를 읽지 않고 언두로그의 데이터를 읽어서 반환한다. 즉, 격리 수준에 따라 보여주는 데이터가 다르다.
언두 로그 모니터링
대용량 데이터 처리
MySQL 5.5 이전 버전에서는 언두 로그 공간은 줄어들지 않았다. 만약 1억개의 레코드가 저장된 테이블을 DELETE로 삭제한다면 1억개의 레코드에 대한 백업을 언두 로그에 저장한다. 즉, 테이블의 크기만큼 언두 로그 공간이 증가하게 된다.
긴 시간 트랜잭션 유지
트랜잭션이 긴 시간 유지될 경우에도 언두 로그 공간이 급격히 증가할 수 있다. 트랜잭션이 완료됐다고 해당 트랜잭션이 생성한 언두 로그를 즉시 삭제할 수 있지 않다. 만약 특수한 이유로 트랜잭션이 완료되지 않고 방치된다면 InnoDB 스토리지 엔진은 트랜잭션이 시작된 시점부터 생성된 언두 로그를 계속 보존할 것이다. 디스크의 언두 로그 공간은 계속 증가하게 될 것이다. 트랜잭션이 유지되는 사이에 변경된 레코드를 빈번히 조회한다면 InnoDB 스토리지 엔진은 언두 로그의 이력을 필요한 만큼 스캔해야 필요한 레코드를 찾을 수 있다. 때문에 쿼리 성능 저하를 유발한다.
언두 테이블스페이스
언두 로그를 저장하는 공간을 언두 테이블스페이스라 한다. 하나의 MySQL 서버에 여러 개의 언두 테이블스페이스가 존재할 수 있다. 하나의 언두 테이블 스페이스는 1~128개의 롤백 세그먼트를 가지며, 롤백 세그먼트는 1개 이상의 언두 슬롯을 가진다.
하나의 롤백 세그먼트는 InnoDB 페이지 크기를 16Byte로 나눈 값의 개수만큼 언두 슬롯을 가진다. 예를 들어 InnoDB 페이지가 16KB라면 16KB / 16B = 1K(1024) 개의 언두 슬롯을 가지게 된다. 하나의 트랜잭션이 필요로 하는 언두 슬롯은 DML에 따라 최대 4개이다. 일반적인 트랜잭션이 2개의 슬롯을 사용한다 가정하면 최대 동시 처리 가능한 트랜잭션의 개수를 계산할 수 있다.
언두 슬롯의 개수는 동시 처리 가능한 트랜잭션과 관련이 있다. 언두 슬롯이 부족한 경우 트랜잭션을 시작할 수 없는 문제가 발생할 수 있다. 언두 테이블 스페이스 개수(innodb_undo_tablespaces), 롤백 세그먼트 개수(innodb_rollback_segments) 등 언두 로그 관련 시스템 변수를 변경해 적절한 언두 슬록 개수를 설정해야 한다.
버전별 언두 테이블스페이스
5.6 이전
언두 로그가 시스템 테이블 스페이스(ibdata.ibd)에 저장됐다. 시스템 테이블스페이스의 언두로그는 MySQL서버가 초기화될 때 생성되기 떄문에 확장의 한계가 있다.
5.6
innodb_undo_tablespaces 시스템 변수가 도입되었다. 이 값을 2보다 큰 값으로 설정하면 별도의 언두 로그 파일을 사용한다.
8.0
이전 버전에서는 innodb_undo_tablespaces 시스템 변수의 값이 0이면 여전이 시스템 테이블 스페이스에 언두 로그를 저장했었다. innodb_undo_tablespaces 시스템 변수를 Deprecated하여 언두 로그는 항상 별도의 로그 파일에 기록된다.
Undo tablespaces truncate
언두 테이블 스페이스 공간을 필요한 만큼 남기고 과도하게 할당된 공간을 운영체제로 반납하는 것이다. 자동과 수동 두 가지 방법이 있다.
자동 모드
트랜잭션이 커밋되면 언두 로그의 복사된 백업은 불필요해진다. InnoDB 스토리지 엔진의 퍼지 스레드는 주기적으로 불필요한 언두 로그를 삭제한다. 이 작업의 빈도를 변경하려면 innodb_purge_rseg_truncate_frequency 값을 조정하면 된다.
수동 모드
언두 테이블스페이스를 비활성화해서 더이상 사용되지 않도록 설정하면 퍼지 스레드는 비활성화된 언두 테이블스페이스를 찾아 운영체제에 반납한다. 반납이 완료되면 언두 테이블스페이스를 다시 활성화 해야한다.
// 언두 테이블스페이스 비활성화
mysql > ALTER UNDO TABLESPACE tablespace_name SET INACTIVE;
// 퍼시 스레드에 의해 언두 테이블스페이스 truncate
mysql > ALTER UNDO TABLESPACE tablespace_name SET ACTIVE;
// 다시 활성화
수동 모드는 3개 이상의 언두 테이블스페이스가 있어야 작동한다.
체인지 버퍼
레코드가 INSERT 되거나 UPDATE될 때 데이터 파일 변경 작업뿐만 아니라 해당 테이블에 포함된 인덱스를 업데이트하는 작업도 필요하다. 그런데 인덱스 업데이트는 디스크 랜덤 IO가 발생하기 때문에 부담이 된다. 그래서 InnoDB는 변경해야할 인덱스 페이지가 버퍼 풀에 있다면 바로 업데이트를 수행하지만 디스크 읽기까 필요하다면 즉시 업데이트 하지 않고 버퍼에 저장하고 사용자에게 결과를 반환한다. 이때 사용하는 버퍼가 체인지 버퍼이다.
유니크 인덱스는 체인지 버퍼를 사용할 수 없다. 체인지 버퍼 머지 스레드는 임시로 저장된 인덱스 레코드 조각을 백그라운드로 병합한다.
'Database' 카테고리의 다른 글
[MySQL] 트랜잭션 (0) | 2023.03.08 |
---|---|
[MySQL] InnoDB 스토리지 엔진 아키텍처 - 4 (0) | 2023.03.01 |
[MySQL] InnoDB 스토리지 엔진 아키텍처 - 2 (2) | 2023.02.01 |
[MySQL] InnoDB 스토리지 엔진 아키텍처 - 1 (0) | 2023.01.11 |
[MySQL] MySQL 쿼리 실행 구조 (0) | 2023.01.10 |