본 문서에서는 주요 스토리지 엔진인 InnoDB Architecture 중 In-Memory Structure에 대해 다루도록 하겠습니다.
In-Memory Structure의 주요 구성 요소는 다음과 같으며, 각각 순서대로 알아보도록 하겠습니다.
- Buffer Pool
- Change Buffer
- Adaptive Hash Index
- Log Buffer
Buffer Pool
InnoDB Buffer Pool은 테이블 및 인덱스 Data의 캐싱을 목적으로 하는 메인 메모리 영역입니다. Buffer Pool에는 테이블 및 인덱스 Data 뿐만 아니라 아래 그림과 같이 다양한 유형의 Data 역시 캐싱되며 Buffer Pool List를 이용하여 목록을 관리합니다.
Buffer Pool을 사용하면 자주 사용하는 Data는 메모리에서 직접 Access 할 수 있으므로 처리 속도가 빨라집니다. Buffer Pool이 클수록 Data를 메모리에서 Access 할 수 있으므로 In-Memory Database처럼 동작 가능합니다. 즉, Buffer Pool의 크기는 시스템 성능에 매우 중요하며, Database 전용 Server의 경우에는 물리 메모리의 80%까지 Buffer Pool에 할당되는 경우가 많습니다.
Buffer Pool은 대용량 읽기 작업의 효율성을 위해 Page 단위로 구성되며, 해당 Page들은 Linked List 구조를 사용하여 효율적으로 Buffer Pool을 관리합니다.
InnoDB의 경우 Data에 Access할 때 우선 Buffer Pool을 확인합니다. 원하는 Data를 찾지 못하면 Data 파일로부터 Page를 읽은 후 Buffer Pool List에 추가합니다.
Buffer Pool(메모리)에 모든 Data를 담을 수는 없으므로, 자주 사용되는 Data 위주로 관리하기 위해 LRU 알고리즘이 사용됩니다.
📢 LRU 알고리즘은 Buffer Pool의 각 Page를 리스트로 연결하여 Page에 Access 할 때마다 대상의 Page를 리스트의 맨 앞(MRU:Most Recently Used)으로 이동시킵니다. 사용되지 않은 Page는 리스트의 말단(LRU:Least Recently Used)으로 이동되며 Buffer Pool의 용량을 초과한 것은 메모리에서 삭제합니다.
Change Buffer (구 버전 - Insert Buffer)
Change Buffer는 InnoDB Buffer Pool에 포함되는 영역으로, Secondary Index Page의 변경 내용을 캐싱하기 위한 임시 공간입니다. (디스크에서의 Change Buffer는 System Tablespace 영역에 존재합니다.)
Insert, Update 또는 Delete 등의 DML 작업은 Secondary Index에 대한 변경작업을 필요로 하므로 많은 디스크 리소스를 필요로 합니다. 변경해야 할 Secondary Index의 Page가 Buffer Pool에 존재할 경우 바로 메모리 내에서 변경 작업이 가능하지만, Page가 Buffer Pool에 없는 경우에는 변경 내역만을 Change Buffer에 저장, 향 후 적용하는 방식을 통해 성능을 향상합니다.
이렇게 Change Buffer에 저장된 변경내역은 추후 다른 Read 작업에 의해 해당 Page가 Buffer Pool에 로드될 때 Merge 됩니다. 이러한 동작 방식으로 인해 디스크에서 Buffer Pool로 Secondary Index Page를 읽는 데 필요한 I/O를 줄일 수 있습니다.
해당 Merge 작업은 InnoDB의 Main Thread에 의해 수행되며, Database Server가 Idle 상태 혹은 Slow Shutdown 중에 동작합니다.
📢 Slow Shutdown 이란 완료하기 전에 추가로 InnoDB Flush 작업을 수행하는 종료 유형으로 클린 종료라고도 합니다. 종료 자체는 더 오래 걸릴 수 있지만 시작 시 시간이 절약됩니다.
Change Buffer는 Buffer Pool 영역을 공유해서 사용하기 때문에 Change Buffer로 인해 Data Page를 캐시 하는 공간이 줄어들 수 있습니다. Data Set이 Buffer Pool에 거의 맞거나, Secondary Index 수가 적은 경우에는 Change Buffer 기능을 비활성화하는 것이 좋습니다. (Change Buffer는 Buffer Pool에 없는 Page에만 적용되기 때문에 해당 기능에 대한 효과가 없습니다.)
또한 innodb_change_buffering
System Variable을 통해 Change Buffer에 저장되는 변경내역의 유형을 정의할 수 있으며, INSERT
, DELETE
, PURGE
작업에 대해 버퍼링을 활성화하거나 비활성화할 수 있습니다.
📢 Unique Index는 메모리와 디스크에 동일한 Data가 있는지 확인하여 고유성을 판단해야 하기 때문에 Data를 캐시에 로드해서 비교해야 하므로 Change Buffer를 사용하지 않습니다.
Adaptive Hash Index
Chnage Buffer와 마찬가지로, InnoDB는 Buffer Pool 공간의 일정 부분을(1/64) Adaptive Hsah Index라는 공간으로 사용합니다.
Adaptive Hash Index는 B-Tree Index의 한계를 보완하기 위한 InnoDB의 주요 기능으로, 자주 사용되는 컬럼을 해시로 정의하여 B-Tree Index를 이용하지 않고 직접 Data에 Access 할 수 있습니다.
이 기능을 통해 InnoDB는 트랜잭션 기능이나 신뢰성의 저하 없이 Buffer Pool에 대한 In-Memory Database와 같은 작업 성능을 낼 수 있습니다.
📢 여타 RDBMS와 마찬가지로, MySQL의 대표적인 인덱스는 B-Tree입니다. Data는 Primary Key 순으로 정렬되어 관리되고, Secondary Index는 PK와 Index Key의 조합으로 정렬이 되어 있습니다.
Adaptive Hash Index는 “Index Key 값”과 해당 Index Key 값이 저장된 “Data Page 주소”로 관리되며, 자주 Access 하는 Index Page에 대해서만 생성됩니다.
“Index Key 값”은 B-Tree Index의 ID와 실제 Key 값의 조합으로 생성되며, “Data Page 주소”는 실제 Key 값이 저장된 Data Page의 메모리 주소(Buffer Pool에 로딩된 Page 주소)를 의미합니다.
사용자는 innodb_adaptive_hash_index
System Variable을 사용하여 해당 기능을 on/off 할 수는 있지만, 자주 사용되는 Data를 Optimizer가 판단하여 Hash Key로 만들기 때문에 대상을 임의로 선정할 수 없어 제어가 어렵습니다.
Adaptive Hash Index에 대한 Access는 여러 테이블의 조인과 같은 Heavy 한 작업에서 경합의 원인이 될 수 있으며, Like 연산자와 ‘%’를 사용한 쿼리에서의 이점도 없습니다. 이와 같이 이점을 얻지 못하는 경우라면 해당 기능을 사용하지 않도록 설정하여 부하를 줄일 수 있습니다.
Log Buffer (구 버전 - Redo Log Buffer)
Log Buffer는 Redo Log 파일에 기록할 Data를 보관하는 메모리 영역입니다.
InnoDB는 Buffer Pool의 Data를 변경할 때 먼저 관련 변경사항을 Log Buffer에 기록한 후, 설정된 주기 혹은 트랜잭션 Commit시점에 디스크로 내려씁니다. (Force-log-at-commit 원칙에 부합합니다.)
Log Buffer의 크기는 innodb_log_buffer_size
System Variable을 통해 설정할 수 있으며, Log Buffer의 내용은 주기적으로 디스크로 Flush 됩니다. Log Buffer의 사이즈를 증가시키면 트랜잭션이 Commit 되기 전에 Redo Log Data를 디스크에 쓸 필요 없이 대용량 트랜잭션을 실행할 수 있습니다. 반대로 Redo Log 파일이 너무 작아은 경우에는 체크포인트가 자주 발생하여 변경된 Data를 디스크에 내려쓰는 일이 많아집니다.
Buffer Pool의 변경된 Data는 WAL 원칙에 따른 체크포인트 메커니즘에 따라, Redo Log가 디스크에 기록된 후에 디스크에 기록됩니다. innodb_flush_log_at_trx_commit
System Variable은 Log Buffer의 내용이 디스크에 기록되고 Flush 되는 방법을 제어하며, innodb_flush_log_at_timeout
는 Flush 빈도(시간)를 제어합니다.
innodb_flush_log_at_trx_commit
Log Buffer의 내용을 디스크에 Flush 하는 방법을 제어하기 위한 innodb_flush_log_at_trx_commit
의 설정 값은 0
, 1
, 2
가 있습니다. 각각의 값에 따른 디스크에 Flush 방식은 다음과 같습니다.
- 0 : Commit과 관계없이 매초 Redo Log를 기록하고 디스크에 Flush 합니다. MySQL 및 노드 장애시 장애 발생전 최대 1초 동안의 트랜잭션 내용이 유실될 수 있습니다.
- 1 : Commit 이 수행될 때마다 Redo Log를 기록하고 디스크에 Flush합니다. 잦은 Write 및 Flush 수행으로 디스크에 부하를 주어 성능에 영향을 받을 수 있지만, 장애 발생 시 완료된 트랜잭션에 대한 Data를 보장합니다.
- 2 : Commit 수행 시마다 Log Buffer의 Redo Log가 OS Cache에 작성되고, Disk Flush는 1초 간격으로 수행합니다. MySQL에만 장애가 발생하였다면 OS Cache에 저장된 트랜잭션 내용은 Redo Log에 반영될 확률이 높지만, MySQL이 동작하는 노드에 문제가 생기는 경우에 대한 최대 1초 동안의 트랜잭션 내용은 유실될 수 있습니다.
- 일반적으로 1로 설정하여 장애로부터 Data 유실을 최소화합니다.
System Variable
Parameter | Default Value | Range | Description |
innodb_change_buffering | all | none, inserts, deletes, changes, purges, all | InnoDB에서 Change Buffering을 수행 여부를 나타냅니다. • all : Default값으로, Buffer Insert, Delete-marking 연산 및 Purge 작업 • none : Buffering 하지 않음 • inserts : Buffer Insert 작업 • deletes : Buffer Delete-marking 작업 • changes : Buffer Insert와 Delete-marking 작업을 모두 • purges : Background에서 발생하는 Buffer Physical Deletion 작업 |
innodb_adaptive_hash_index | ON | ON, OFF | • InnoDB에서 Adaptive Hash Index 사용 여부를 나타냅니다. • 기본적으로 활성화되며, Server를 재시작하지 않고 ‘SET GLOBAL’문을 사용하여 이 값을 수정할 수 있습니다. |
innodb_log_buffer_size | 16777216(16MB) | 1048576 ~ 4294967295 | • InnoDB에서 디스크에 로그파일을 작성하는데 사용하는 Buffer의 크기를 가리킵니다. Log Buffer를 크게 설정하면 트랜잭션이 Commit 되기 전에 디스크에 로그를 작성하지 않고 많은 트랜잭션을 실행할 수 있습니다. • 많은 Row에 대하여 Update, Delete, Insert 등의 작업을 하는 트랜잭션이 있는 경우에는 이 값을 크게 설정하면 디스크 I/O를 줄일 수 있습니다. |
innodb_flush_log_at_trx_commit | 1 | 0, 1, 2 | • 이 System Variable을 통해 트랜잭션의 Commit 관련 로그를 Write&Flush 하는 시점을 조절할 수 있습니다. • 값에 따라 Data의 유실여부와 I/O 성능이 달라지므로 Data의 중요도와 성능을 고려하여 값을 설정해야 합니다. |
innodb_flush_log_at_timeout | 1 | 1 ~ 2700 | 설정한 N초마다 로그를 Write하고 Flush 합니다. 이 System Variable을 사용하여 Flush를 줄일 수 있습니다. |
기획 및 글 | 기술기획팀
이미지 제작 | 디자인그룹 이민석
'엑셈 경쟁력 > DB 인사이드' 카테고리의 다른 글
DB 인사이드 | MySQL Architecture - 8. InnoDB : 동작 원리 (3) | 2022.07.27 |
---|---|
DB 인사이드 | MySQL Architecture - 7. InnoDB : On-Disk Structure (0) | 2022.07.27 |
DB 인사이드 | MySQL Architecture - 5. SQL 처리과정 (4) | 2022.06.30 |
DB 인사이드 | MySQL Architecture - 4. Memory (0) | 2022.06.30 |
DB 인사이드 | MySQL Architecture - 3. Thread (0) | 2022.06.30 |
댓글