관리 메뉴

피터의 개발이야기

[MySQL] InnoDB의 구조와 Caching을 이용한 포퍼먼스 향상에 대한 이해 본문

Database/MySQL

[MySQL] InnoDB의 구조와 Caching을 이용한 포퍼먼스 향상에 대한 이해

기록하는 백앤드개발자 2023. 8. 1. 23:46
반응형

ㅁ 개요

 MySQL을 사용하면서 InnoDB에 대해서 잘 이해하지 못한 부분이 있어서 공부를 하게 되었다. 백엔드 입장에서 시스템 포퍼먼스를 위해 캐싱기능을 이용하는데, InnoDB도 Memory를 이용한 캐싱처리를 통해 DB 포퍼먼스를 향상 시켰음을 알게 되었다. 이번 글은 InnoDB의 구조를 이해하고 세부적인 처리 방식에 대해서 정리하였다.

 

 

ㅁ InnoDB의 구조

 

ㅇ  Buffer Pool를 이용한 성능 향상

Buffer Pool은 MySQL의 DB Engine인 InnoDB가 Table Caching  Index Data Caching을 위해 이용하는 Memory 공간이다. Buffer Pool 크기가 클수록 상대적으로 Disk에 접근하는 횟수가 줄어들기 때문에 DB의 성능이 향상된다.

 

ㅇ Memory 장애를  대비를 위해 Redo Log를 바탕으로  Recovery

Buffer Pool은 Memory 공간이기 때문에 MySQL에 장애가 발생하면 Buffer Pool 내용은 사라지고 Transaction의 유실로 이어질 수 있다. 이러한 유실을 방지하기 위해서 사용되는 File이 Redo Log이다. Redo Log는 Transaction 내용을 기록하고 있다가 MySQL 장애발생시 Redo Log에 기록된 Transaction 내용을 바탕으로 MySQL을 장애가 발생하기 이전 시점으로 Recovery한다.

 

ㅇ Checkpoint

InnoDB는 Transaction 내용은 계속 Buffer Pool과 Redo Log에 쌓지 않고, 주기적으로 또는 Redo Log가 가득차면 Buffer Pool에 기록된 Transaction 내용을 실제 Disk에 반영한다. 이러한 동작을 Checkpoint라고 한다. Redo Log는 2개의 파일을 번갈아가며 이용한다. Redo Log가 가득차면 가득찬 Redo Log는 놔두고 이용하지 않고 있던 Redo Log에 Transaction 내용을 기록한다. 가득찬 Redo Log는 Checkpoint 동작을 수행하고 비워진다.

 

ㅇ Disk 병목을 예방하기 위한 Log Buffer

Redo Log도 File이기 때문에 Transaction을 처리할때 마다 바로 Redo Log에 직접 Transaction 내용을 쓴다면 잦은 Disk 접근으로 인한 성능저하가 발생할 수 있다. InnoDB는 이러한 문제는 해결하기 위해서 Redo Log의 Cache 역할을 수행하는 Log Buffer에 Transaction 내용을 기록하고 한꺼번에 Redo Log에 기록한다. Log Buffer에 있는 Transaction 내용은 InnoDB의 Write 동작으로 인해서 OS의 Disk Cache로 전달되고 Inno DB의 Flush 동작으로 인해서 Redo Log 파일에 저장된다. InnoDB의 Write 및 Flush 동작은 InnoDB의 설정에 따라 수행되는 시점이 달라진다.

 

Undo log

Undo log는 단일 트랜잭션과 관련된 Undo log 레코드의 집합이다. undo log 레코드에는 클러스터드 인덱스 레코드의 트랜잭션에 의한 제일 최근의 변경사항의 변경 전 데이터를 저장한다. 만약 다른 트랜잭션이 변경 전 데이터를 읽기를 원한다면 undo log 레코드에서 변경 전 데이터를 읽는다.

 

MVCC(Multi-Version Concurrency Control)

 일반적인 RDBMS는 변경 전의 레코드를 Undo log에 백업해둔다. 그러면 변경 전/후 데이터가 모두 존재하므로, 동일한 레코드에 대해 여러 버전의 데이터가 존재하는데, 이를 MVCC(Multi-Version Concurrency Control, 다중 버전 동시성 제어)라고 부른다. MVCC를 통해 트랜잭션이 롤백된 경우에 데이터를 복원할 수 있을 뿐만 아니라, 서로 다른 트랜잭션 간에 접근할 수 있는 데이터를 세밀하게 제어할 수 있다. 각각의 트랜잭션은 순차 증가하는 고유한 트랜잭션 번호가 존재하며, 백업 레코드에는 어느 트랜잭션에 의해 백업되었는지 트랜잭션 번호를 함께 저장한다. 그리고 해당 데이터가 불필요해진다고 판단하는 시점에 주기적으로 백그라운드 쓰레드를 통해 삭제한다.

 

 

ㅁ HLL(History List Length)

Aurora MySQL은 On-premise MySQL 환경과 동일하게 REPEATABLE READ isolation level이 Default로 설정되어 있다. REPEATABLE READ 환경은 쿼리 실행 시점의 결과와, 실행 완료 시점의 결과가 동일해야 하기 때문에, 스냅샷 형태로 해당 시점의 결과를 저장하게 된다. 동시성이 높은 환경에서, 롱쿼리가 발생하게 되어 오랜 시간 시점데이터가 유지될수록, History Legnth 수치가 상승하게 된다.

History Length가 높아질수록, 오래된 데이터 스냅샷으로 인해 다른 조회 쿼리들도 시점 데이터를 통해 걸러내는 과정이 추가되면서, 검색 비효율이 발생하고 지연이 발생할 수 있다. 극단적으로 트래픽이 높은 서비스 환경에서는 약간의 지연으로 고객들의 불편함이 커지고, 서비스 장애의 원인이 될 수 있기 때문에, 모니터링해야 하는 필수적인 지표 중 하나이다.

 

ㅁ 옵션을 통한 History Length 상승 관리

위에서 설명드린 바와 같이, History Length가 서비스에 영향을 줄 수 있는 중요한 요소 중 하나이기 때문에, 기존 on-premise MySQL에서는 이를 관리하기 위해 아래의 옵션을 통해 긴 조회쿼리를 실행해야 하는 상황에서 session isolation level을 통해 관리가 가능했습니다.

-- Isolation level 변경 (REPATABLE READ -> READ COMMITTED)
mysql> set session transaction isolation level read committed;

 

ㅁ 변경 데이터의 저장 로직

https://blog.ex-em.com/1700

1. Query 조건에 맞는 Data가 Buffer Pool에 존재하는지 확인한다.

 ㄴ Data가 없으면 Table Data에서 Buffer Pool로 해당 Data를 로드한다.

 

2. 변경 시 기존 Data를 백업한다.

 ㄴ Rollback을 위해 Undo Log에 Data를 저장하여 트랜잭션이 가능해진다.

 

3. Undo Log에 백업 후, Query 내용에 따라 Buffer Pool에 변경된 Data가 저장된다. 이때 변경된 Data는 디스크로 Flush 되지는 않은 상태이며 이를 Dirty Page라고 한다.

 

4. 이후, 특정 조건에 의해 체크포인트 발생 시 비로소 Dirty Page의 Data가 디스크로 Flush 된다.

 ㄴ 먼저 Doublewrite Buffer에 Buffer Pool에 변경된 Page를 모아서 한 번에 Write 한다.

 ㄴ 마지막으로 Buffer Pool의 변경된 Page를 개별적으로 Data 파일에 Write 합니다.

📢 Doublewirte Buffer는 Buffer Pool로부터 Flush된 Page를 Data 파일에 쓰기 전에 저장하는 영역으로 Buffer라는 명칭과 달리 실제로는 디스크 영역에 존재한다. Data 파일에 Page를 쓰는 도중 문제가 발생하면 Doublewirte Buffer을 통해 해당 Page를 복구할 수 있다.

 

ㅁ 트랜잭션 로그 관리(Redo Log & Binlog)

  InnoDB는 미리 쓰기 로그(WAL: Write Ahead Log) 전략을 채택하므로, Data를 내려쓰기 전에 Log Buffer에 Redo Log(트랜잭션의 내용)을 먼저 기록합니다. 그리고 복제 구성 또는 특정 시점으로의 Data 복구 등에 사용하기 위해 Binlog(Data 변경사항과 소요시간 등을 포함)를 작성한다.

  MySQL은 Redo Log와 Binlog 간의 데이터 일관성 문제를 해결하기 위해 2PC(Two-Phase Commit Protocol)를 사용하며, Prepare와 Commit으로 나누어 진행합니다.

 

1-1. Buffer Pool의 Data가 변경되면 Redo Log를 생성하여 Log Buffer에 추가합니다.

1-2. Redo Log 작성 후에 트랜잭션을 언제든지 Commit을 할 수 있는 prepare 상태가 되고, Log Buffer의 Redo Log를 디스크의 Redo Log File로 Flush 한다.

 

2-1. 그리고 Data 변경사항 관련하여 Binlog Cache에 Binary Log(binlog)를 작성한다.

2-2. 작성된 Binlog를 디스크로 동기화하고 Binlog Cache를 비운다.

 

3. Binlog 관련 정보를 Redo Log File에 기록하고 ACK와 Commit을 수행한다.

 

 

ㅁ 함께 보면 좋은 사이트

 

DB 인사이드 | MySQL Architecture - 8. InnoDB : 동작 원리

앞서 MySQL의 InnoDB Architecture와 그 구성 요소들에 대해 알아보았습니다. 본 문서에서는 해당 내용을 바탕으로 MySQL의 Connection 생성 및 사용자 요청 처리, 주요 Thread의 동작 방식에 대한 내용을 InnoDB

blog.ex-em.com

 

MySQL Buffer Pool, Redo Log, Log Buffer

MySQL의 Buffer Pool, Redo Log 및 Log Buffer를 분석한다.

ssup2.github.io

 

 

Aurora MySQL DB 클러스터에서 느린 SELECT 쿼리 문제 해결

Amazon Aurora MySQL 호환 에디션 DB 클러스터가 있는데 SELECT 쿼리를 사용하여 데이터베이스에서 데이터를 선택하고 싶습니다. DB 클러스터에서 SELECT 쿼리를 실행하면 쿼리가 느리게 실행됩니다. SELECT

repost.aws

 

Aurora MySQL History Length 상승을 예방하는 방법

History Length란? Aurora MySQL은 On-premise MySQL 환경과 동일하게 REPEATABLE READ isolation level이 Default로 설정되어 있습니다. REPEATABLE READ 환경은 쿼리 실행 시점의 결과와, 실행 완료 시점의 결과가 동일해야

martin-son.github.io

반응형
Comments