개발 메모장
InnoDB 본문
오늘은 MySQL의 스토리지 엔진 중 하나인 InnoDB에 대해 알아보겠습니다.
1. InnoDB 특징
InnoDB는 다음과 같은 특징을 가집니다.
- 레코드 기반의 잠금 제공: 행 수준의 잠금(Record Lock)을 통해 동시성을 향상시키고, 테이블 전체 잠금과 관련된 성능 문제를 줄입니다.
- 프라이머리 키에 의한 클러스터링: 프라이머리 키를 기준으로 데이터를 클러스터링하여 데이터 접근 성능을 높입니다.
- 외래 키 지원: 참조 무결성(Foreign Key Constraints)을 제공하여 데이터베이스의 관계형 모델을 지원합니다.
- MVCC (Multi-Version Concurrency Control): 다중 버전 동시성 제어를 사용해 트랜잭션 격리 수준에서 잠금 없이 일관된 읽기(Consistent Read)를 제공합니다.
- 자동 데드락 감지: 트랜잭션 충돌 시 데드락을 자동으로 감지하고 트랜잭션을 롤백하여 시스템의 안정성을 유지합니다.
- 자동화된 장애 복구: 시스템 장애나 비정상 종료 시 자동으로 데이터를 복구하는 기능을 지원하여 안정성을 보장합니다.
2. InnoDB 구성
InnoDB는 다음과 같은 요소들로 구성됩니다:
- 버퍼 풀(Buffer Pool)
- 리두 로그(Redo Log)
- 더블 라이트 버퍼(Double Write Buffer)
- 언두 로그(Undo Log)
- 체인지 버퍼(Change Buffer)
- 어댑티브 해시 인덱스(Adaptive Hash Index)
2.1 버퍼 풀 (Buffer Pool)
디스크 I/O 성능을 향상시키기 위해 자주 사용하는 데이터 파일이나 인덱스 정보를 캐시하는 공간입니다. 글로벌 메모리 영역에 존재합니다.
- 페이지 단위로 데이터를 저장하며, 3개의 리스트로 관리됩니다.
- Free 리스트: 비어 있는 페이지를 관리하는 목록입니다.
- LRU 리스트: 자주 사용되는 페이지는 MRU(Most Recently Used), 덜 사용되는 페이지는 LRU(Least Recently Used) 리스트에 저장하여 페이지의 수명을 관리합니다.
- Flush 리스트: 더티 페이지(Dirty Page)를 디스크에 기록하기 위한 페이지 목록을 관리하며, 주기적인 체크포인트를 통해 디스크와 동기화합니다.
2.2 리두 로그 (Redo Log)
트랜잭션 동안 발생한 데이터 변경 내용을 기록한 로그입니다.
- 리두 로그 버퍼는 글로벌 메모리 영역에 위치하고, 리두 로그 파일은 디스크에 기록됩니다.
- Write-Ahead Logging(WAL)을 사용하여, 데이터 변경이 일어나면 먼저 리두 로그에 기록된 후, 디스크에 실제로 데이터를 기록합니다.
- LSN(Log Sequence Number)는 로그의 순서를 관리하며, 고정 크기 파일로 연결된 순환 구조를 통해 로그를 관리합니다. 로그가 가득 차면 오래된 로그를 덮어씁니다.
- 시스템 충돌 시, 리두 로그를 사용해 변경 내용을 복구합니다.
2.3 더블 라이트 버퍼 (Double Write Buffer)
디스크 쓰기 작업 중 페이지 손상을 방지하기 위한 버퍼입니다.
- 버퍼 풀에서 더티 페이지를 디스크로 기록할 때, 먼저 데이터를 Double Write Buffer에 기록한 후 실제 디스크에 기록합니다.
- 쓰기 중 오류 발생 시, Double Write Buffer를 이용해 복구할 수 있습니다.
2.4 언두 로그 (Undo Log)
트랜잭션이 데이터를 변경하기 이전의 상태를 기록하여 롤백 작업을 가능하게 하는 로그입니다. 글로벌 메모리에 존재하며 필요 시 디스크에 플러시 되었다가 트랜잭션의 종료 이후 디스크에서 삭제됩니다.
2.5 체인지 버퍼 (Change Buffer)
인덱스에 대한 변경 사항을 임시로 저장하는 버퍼입니다.
2.6 어댑티브 해시 인덱스 (Adaptive Hash Index, AHI)
자주 사용되는 페이지에 대한 해시 인덱스입니다. InnoDB는 버퍼 풀 내에서 자주 참조되는 페이지를 감지하여, 해당 페이지에 대한 해시 인덱스를 자동으로 생성합니다.
3. InnoDB의 동작 과정
3.1 데이터 읽기 시
- AHI 확인: AHI가 활성화되어 있으면, InnoDB는 AHI를 먼저 확인하여 요청된 데이터의 위치를 찾습니다. AHI에 데이터가 존재하지 않으면, B-Tree 인덱스를 조회합니다.
- 버퍼 풀 확인: 버퍼 풀 내에서 요청된 데이터 페이지가 캐시되어 있는지 확인합니다. 버퍼 풀에 페이지가 존재하면 해당 페이지를 통해 데이터 읽기를 수행하고 LRU 리스트를 업데이트합니다.
- 디스크에서 데이터 읽기: 디스크에서 데이터를 읽은 후 버퍼 풀에 캐시합니다. 이 때 Free 리스트에서 찾아 비어 있는 페이지가 없으면, LRU 리스트를 사용하여 오래된 페이지를 선택해 교체합니다.
3.2 쓰기 시
- 리두 로그 기록: 데이터가 변경되면, 먼저 리두 로그에 변경 내용을 기록합니다.
- 언두 로그 기록: 버퍼 풀 페이지의 변경 이전 내용을 기록합니다.
- 버퍼 풀 기록: 리두 로그의 변경 사항을 통해 버퍼 풀 페이지를 버티 페이지로 변경합니다.
- 더블 라이트 버퍼 사용: 버퍼 풀의 플러시 전 더블 라이브 버퍼에 기록하여 쓰기 작업 오류를 대비합니다.
- 버퍼 풀의 플러시 및 체크포인트: Flush 리스트를 사용하여 더티 페이지를 디스크에 기록합니다. 이는 주기적인 체크포인트 작업을 통해 수행됩니다.
이번 글에서는 MySQL의 InnoDB에 대해 알아보았습니다. InnoDB는 MySQL 8.0부터 기본 스토리지 엔진으로 사용되기 때문에 내부 동작에 익숙해지는 것이 좋을 것 같습니다.
참고자료
'DBMS > MySQL' 카테고리의 다른 글
MySQL 아키텍처 (0) | 2024.08.30 |
---|