MySQL InnoDB Buffer Pool 구조와 페이지 교체 알고리즘 분석

MySQL InnoDB Buffer Pool 구조와 페이지 교체 알고리즘 분석

MySQL InnoDB 스토리지 엔진에서 성능을 좌우하는 가장 핵심적인 요소는 Buffer Pool이다.
디스크 I/O를 최소화하고 트랜잭션 처리 성능을 높이기 위해 InnoDB는 데이터와 인덱스를 메모리에 적극적으로 캐싱하며, 이때 어떤 페이지를 유지하고 어떤 페이지를 내보낼지 결정하는 페이지 교체 알고리즘이 매우 중요한 역할을 한다.
이 글에서는 InnoDB Buffer Pool의 내부 구조와 페이지 교체 메커니즘을 실무 관점에서 심층 분석한다.

1. InnoDB Buffer Pool의 역할과 기본 개념

Buffer Pool은 InnoDB가 디스크의 데이터 페이지와 인덱스 페이지를 메모리에 캐싱하는 영역이다.
쿼리가 실행될 때 필요한 페이지가 Buffer Pool에 존재하면 디스크 접근 없이 즉시 처리되며, 이는 성능에 결정적인 차이를 만든다.

Buffer Pool의 주요 역할은 다음과 같다.

  • 데이터 및 인덱스 페이지 캐싱
  • 디스크 I/O 감소
  • 변경된 페이지(Dirty Page) 관리
  • 읽기 중심, 쓰기 중심 워크로드 모두에 대응

일반적으로 InnoDB 성능 튜닝의 출발점은 Buffer Pool 설정이라고 해도 과언이 아니다.

2. Buffer Pool의 내부 구조

InnoDB Buffer Pool은 단순한 메모리 덩어리가 아니라, 여러 구조로 나뉘어 관리된다.

페이지(Page) 단위 관리

  • 기본 페이지 크기: 16KB
  • 데이터 페이지, 인덱스 페이지, undo 페이지 등 모두 동일한 크기
  • Buffer Pool은 수많은 16KB 페이지의 집합

Free List

  • 아직 사용되지 않은 빈 페이지 목록
  • 디스크에서 새로운 페이지를 읽어올 때 사용

LRU List

  • 현재 캐시된 페이지들을 관리하는 핵심 리스트
  • 페이지 교체 알고리즘의 중심

Flush List

  • 변경된 페이지(Dirty Page)를 추적
  • 체크포인트 또는 백그라운드 플러시 시 디스크에 기록

이 세 가지 리스트의 균형이 InnoDB의 안정성과 성능을 결정한다.

3. 전통적인 LRU 방식의 한계

일반적인 LRU(Least Recently Used) 알고리즘은
“가장 오랫동안 사용되지 않은 페이지를 제거한다”는 단순한 원칙을 따른다.

하지만 데이터베이스 워크로드에서는 다음과 같은 문제가 발생한다.

  • 대용량 테이블 Full Scan 발생
  • 일회성 쿼리로 인해 수많은 페이지가 캐시를 오염
  • 기존에 자주 사용되던 핫 데이터가 밀려남

이 현상을 Buffer Pool Pollution이라고 하며, InnoDB는 이를 해결하기 위해 LRU를 그대로 사용하지 않는다.

4. InnoDB의 LRU List 분할 구조

InnoDB는 LRU 리스트를 두 영역으로 나누는 독특한 구조를 사용한다.

  • New Sublist
  • Old Sublist

이 구조는 흔히 Midpoint Insertion LRU라고 불린다.

Old Sublist

  • 새로 읽혀온 페이지가 처음 들어가는 영역
  • 일회성 접근 페이지가 주로 머무는 공간

New Sublist

  • 반복적으로 접근된 페이지가 이동하는 영역
  • 실제 핫 데이터가 유지되는 공간

페이지는 처음 로드될 때 LRU 리스트의 중간 지점(Old 영역)에 삽입되며, 일정 조건을 만족해야 New 영역으로 승격된다.

5. 페이지 승격(Promotion) 조건

페이지가 Old 영역에서 New 영역으로 이동하기 위해서는 다음 조건을 만족해야 한다.

  • 일정 시간 이상 Old 영역에 머문 후 재접근
  • 단순한 연속 스캔이 아닌 반복 접근

이를 통해 InnoDB는
“한 번 스캔된 데이터”와
“실제로 자주 사용되는 데이터”를 구분한다.

이 구조 덕분에 대규모 Full Scan이 발생해도 기존 캐시가 한 번에 밀려나지 않는다.

6. 페이지 교체(Eviction) 과정

Buffer Pool이 가득 차고 새로운 페이지를 로드해야 할 때, InnoDB는 다음 순서로 페이지를 제거한다.

  1. LRU 리스트의 가장 오래된 페이지 후보 선택
  2. 해당 페이지가 Dirty Page인지 확인
  3. Dirty Page인 경우 먼저 디스크로 flush
  4. Clean Page로 전환 후 메모리에서 제거

이 과정은 백그라운드에서 수행되며, 사용자는 직접 체감하지 않지만 성능에 큰 영향을 준다.

7. Dirty Page 관리와 Flush 전략

InnoDB는 쓰기 성능을 높이기 위해 변경된 데이터를 즉시 디스크에 기록하지 않는다.
대신 Dirty Page로 표시하고, 적절한 시점에 묶어서 flush한다.

주요 flush 트리거는 다음과 같다.

  • 체크포인트 진행
  • Dirty Page 비율 증가
  • 메모리 압박
  • 서버 종료 또는 강제 플러시

Dirty Page 비율이 과도하게 높아지면, 갑작스러운 대량 flush로 인해 I/O 스파이크가 발생할 수 있다.

8. Buffer Pool 인스턴스 분할(Buffer Pool Instances)

대규모 서버에서는 Buffer Pool을 여러 인스턴스로 나누어 관리한다.

Buffer Pool Instances의 목적은 다음과 같다.

  • LRU 및 페이지 관리 락 경합 감소
  • 멀티코어 환경에서 확장성 향상
  • 동시 접근 성능 개선

각 인스턴스는 독립적인 LRU, Free, Flush 리스트를 가지며, 워크로드가 분산된다.

9. 실무 튜닝 관점에서의 핵심 포인트

Buffer Pool과 페이지 교체 알고리즘을 이해하면 다음 튜닝 포인트가 중요해진다.

  • Buffer Pool 크기: 전체 메모리의 60~75% 권장
  • Old 영역 비율 조정으로 Full Scan 영향 최소화
  • Dirty Page 비율 모니터링
  • Buffer Pool Instances 적절한 분할
  • Full Scan 쿼리 빈도 점검

특히 OLTP 환경에서는 핫 데이터가 New 영역에 안정적으로 유지되는지가 핵심이다.

10. 정리 및 결론

InnoDB Buffer Pool은 단순한 캐시가 아니라,
LRU 분할 구조와 정교한 페이지 교체 알고리즘을 통해 데이터베이스 성능을 지탱하는 핵심 엔진이다.

핵심 요약

  • Buffer Pool은 16KB 페이지 단위로 관리
  • 전통적인 LRU 대신 New/Old 분할 구조 사용
  • Full Scan으로 인한 캐시 오염 방지
  • 페이지 승격과 교체가 성능 안정성의 핵심
  • 튜닝 없이 기본 설정만으로는 한계 존재

InnoDB 성능 문제의 상당수는 Buffer Pool 구조를 이해하는 것만으로도 원인을 좁힐 수 있다.
운영 환경에 맞는 Buffer Pool 설계와 모니터링이 안정적인 MySQL 서비스를 만드는 가장 중요한 기반이다.

댓글 남기기