MySQL 8.0의 InnoDB Storage Engine에 대한 내용을 정리한 글입니다.
MySQL 공식문서를 기반으로 작성하였으며, 문서에 제공된 내용 외 추가적인 내용들을 정리 했습니다.
InnoDB In-Memory 영역 1: 버퍼 풀(Buffer Pool) - 현재글
InnoDB In-Memory 영역 2: 어댑티브 해시 인덱스(Adaptive Hash Index)
InnoDB In-Memory 영역 3: 체인지 버퍼(Change Buffer)
InnoDB In-Memory 영역 4: 로그 버퍼(Log Buffer)
InnoDB 아키텍처 간략소개
InnoDB는 In-Memory 영역과 On-Disk 영역으로 나뉜다.
In-Memory 영역은 주로 자주 액세스 되는 데이터를 보관하기 위한 용도로서 빠른 액세스를 가능하게 도와준다.
On-Disk 영역은 데이터베이스의 durability(지속성)과 recovery(회복)를 보장하며 효율적인 데이터 액세스를 위한 기능들을 제공한다.
버퍼 풀 (Buffer Pool)
버퍼 풀은 자주 사용되는 데이터를 메모리에서 엑세스 하여 처리 속도가 빨리 지게 끔 해주는 공간이다.
뿐만 아니라 변경된 데이터가 디스크에 저장되기 전에 임시로 보관하는 쓰기 버퍼링 기능도 제공한다.
높은 작업량에서의 효율성을 증가시키기 위해 버퍼 풀을 페이지라는 단위로 쪼개어 구성한다.
페이지(Page)란?
페이지는 여러 레코드의 데이터를 담는 하나의 단위이다.
디스크 내부에 산재되어 있는 레코드에 개별적으로 접근하는 비용을 줄이고 한 번에 여러 레코드를 읽어올 수 있다는 장점이 생기는 것이다.
즉, 페이지를 사용함으로써 InnoDB는 여러 레코드를 하나의 디스크 I/O 작업으로 처리할 수 있게 된다. 이는 개별 레코드를 각각 읽거나 쓰는 것보다 효율적이다.
e.g.)
사용자가 테이블에서 10개의 연속된 레코드를 조회
- 페이지 단위 처리가 없는 경우
- 시스템은 각 레코드를 개별적으로 디스크에서 읽어야 한다.
- 이는 10번의 디스크 I/O 작업을 필요로 하며, 각 작업은 디스크에 대한 별도의 접근을 요구한다.
- 이 방식은 매우 비효율적이다.
- 페이지 단위 처리가 있는 경우 (InnoDB의 방식)
- InnoDB는 페이지 단위로 데이터를 관리합니다. 페이지는 여러 레코드를 포함할 수 있다.
- 사용자가 요청한 10개의 레코드가 모두 하나의 페이지 내에 위치한다면, InnoDB는 단 한 번의 디스크 I/O 작업으로 필요한 모든 레코드를 메모리로 로드할 수 있다.
- 결과적으로, 데이터베이스는 더 적은 수의 디스크 접근으로 필요한 데이터를 빠르게 가져올 수 있으며, 이는 전체적인 성능 향상으로 이어진다.
InnoDB 스토리지 엔진의 경우, 페이지 크기는 16KB가 기본 값이다.(innodb_page_size=16KB)
1. Buffer Pool 관리
버퍼 풀은 드물게 사용되는 데이터를 효율적으로 관리하기 위해 Linked-List 자료구조를 사용한다.
이는 사용빈도가 높은 페이지와 아닌 페이지를 나누어 캐시에 접근하는 빈도 수를 높여, 디스크 I/O작업을 최소화하면서 메모리에서 효율적으로 데이터를 관리하기 위함이다.
즉, LRU(Least Recently User) 알고리즘을 사용하여 버퍼 풀의 페이지를 관리하는 것이다.
버퍼 풀을 관리하기 위한 LRU 알고리즘은 위 이미지와 같다.
버퍼 풀에 있는 페이지를 관리하기 위해 페이지 포인터들을 위 리스트로 관리한다.
버퍼 풀을 관리하는 리스트(이하: 버퍼 풀 리스트)는 두 영역으로 나뉜다.
1. 가장 최근에 엑세스된 새로운 페이지들의 서브리스트(New Sublist)
2. 엑세스 되지 않은 오래된 페이지들의 서브리스트(Old Sublist)
위 두 서브리스트로 나누어 관리함으로써 Old Sublist에는 비교적 오랫동안 사용되지 않은 페이지들이 포함되어 있고, eviction 대상이 된다.
데이터를 읽어오는 과정에서 버퍼 풀이 어떤 식으로 관리되는지 살펴보면 아래와 같다.
2. Buffer Pool 관리 Flow
- 버퍼 풀은 ‘new sublist’와 ‘old sublist’로 구성된다.
- New sublist의 끝과 old sublist의 시작점이 만나는 지점을 midpoint(중간지점)이라고 한다. (= old sublist의 시작점)
InnoDB가 페이지를 버퍼 풀에 처음 읽어올 때. 즉, 버퍼 풀에 페이지가 없어 디스크에서 처음으로 읽어올 때, 이 midpoint에 삽입된다. (= old sublist의 시작 부분에 삽입)
(+ 페이지는 SQL 쿼리를 통해 읽힐 수도 있지만, read-ahead라는 작업으로도 읽힐 수 있다.) - Old sublist에 있는 페이지에 접근하면 페이지가 young 해진다고 표현하기도 하는데,
이는 new sublist의 시작 부분으로 페이지가 이동함을 의미한다.
* 쿼리를 통해 old sublist의 페이지가 읽힌 경우에 바로 페이지가 new sublist로 이동한다.
* 하지만, read-ahead 작업으로 인해 페이지가 읽힌 경우라면 실제 쿼리가 발생하기 이전까지 new sublist로 이동하지 않을 수 있다. (즉, 페이지가 버퍼 풀에서 제거되기 전까지도 아예 이동하지 않을 수 있다.) - 버퍼 풀 내의 페이지들은 접근되지 않을 때 aging된다.aging 된다. old sublist의 시작 부분에 새 페이지가 삽입됨에 따라 aging 된다.
이렇게 사용되지 않고 남은 페이지는 old sublist의 끝에 도달하는 페이지는 결국에 Eviction 되는 것이다.
3. 정리
처음으로 읽힌 페이지가 midpoint에 삽입된 이후에 쿼리에 의해 읽히면, 해당 페이지는 new sublist의 시작 부분으로 이동한다.
New sublist에서 사용되지 않는다면 aging 되고, 새로운 페이지가 삽입되면서 old sublist의 끝으로 밀려나면서 버퍼 풀에서 제거된다.
+) 버퍼 풀은 변경된 데이터를 가진 페이지를 임시로 보관하는 기능도 한다고 앞서 언급했다.
임시로 보관하는 페이지를 실제 디스크에 기록하기 위한 과정이 필요한데, 이 부분은 Redo Log와 깊은 연관관계가 있다.
[Reference]
https://dev.mysql.com/doc/refman/8.0/en/innodb-buffer-pool.html
'DB > MySQL' 카테고리의 다른 글
MySQL, DeadLock..? (주의점: S-Lock이 전파된다.) (1) | 2023.09.19 |
---|