[MySQL] InnoDB 버퍼 풀

신찬규·2024년 6월 24일

MySQL

목록 보기
8/13

InnoDB 버퍼 풀은 디스크의 테이블이나 인덱스를 메모리에 캐시해 두는 공간이다. 또한 쓰기 작업을 버퍼링을 통해 일괄 작업으로 처리할 수 있게 함으로써 디스크의 랜덤 I/O 횟수를 줄일 수 있다.

1. 버퍼 풀 크기

InnoDB 버퍼 풀의 크기는 innodb_buffer_pool_size 시스템 변수를 통해 설정할 수 있다. InnoDB 버퍼 풀은 내부적으로 128MB 청크 단위로 쪼개어 관리되기 때문에 버퍼 풀의 크기는 128MB의 배수이다.

메모리 크기만 충분하다면 innodb_buffer_pool_instances 시스템 변수의 조절을 통해 버퍼 풀을 여러 개의 버퍼 풀 인스턴스로 쪼개어 잠금 경합 현상을 개선할 수 있다.

2. 버퍼 풀 구조

InnoDB 버퍼 풀은 메모리 공간을 페이지 단위로 나누어 관리한다. InnoDB는 페이지들을 관리하기 위해 3개의 자료 구조를 사용하는데, LRU 리스트와 플러시(Flush) 리스트, 프리(Free) 리스트이다.

2.1 LRU 리스트

LRU 리스트는 자주 사용하지 않는 데이터 페이지를 캐시에서 내보내기 위함이다.

LRU 리스트는 New 서브 리스트와 Old 서브 리스트로 나뉘는데, New 서브 리스트는 자주 사용되는 데이터 페이지가 저장되며 Old 서브 리스트는 자주 사용되지 않는 데이터 페이지가 저장된다. 새로운 데이터 페이지가 버퍼 풀에 적재될 때 Old 서브 리스트의 Head에 삽입되는데, 이 지점을 Midpoint라고도 한다. 해당 페이지가 실제로 사용되면 New 서브 리스트의 Head 쪽으로 이동하며, 자주 사용되지 않으면 새로운 데이터 페이지들이 Midpoint에 삽입되면서 점차 Old 서브 리스트의 Tail 쪽으로 이동한다. Tail에 위치한 데이터 페이지들은 Eviction 대상이 된다. 데이터 페이지를 삭제해 추가 공간을 확보하는 작업을 Eviction이라고 한다. 버퍼 풀의 5/8은 New 서브 리스트에 위치하고, 나머지는 Old 서브 리스트에 위치한다.

그렇다면, 왜 새로운 데이터 페이지는 New 서브 리스트가 아닌 Old 서브 리스트에 저장되는 걸까? 이는 새로운 데이터 페이지가 실제 쿼리에 사용되지 않을 수도 있기 때문이다. MySQL은 데이터 페이지를 가져올 때 해당 페이지 뿐만 아니라 주변의 여러 데이터 페이지도 같이 가져오는데, 이를 Read Ahead라고 한다. 특정 데이터 페이지가 사용되면 주변 페이지들도 곧 사용될 것이라고 예상하고 미리 가져오는 것인데, Locality라고 보면 된다.

2.2 플러시 리스트

플러시 리스트는 버퍼 풀의 더티 페이지를 추적하고 관리하기 위해 사용된다. 플러시 리스트는 InnoDB의 내부 미니 트랜잭션에 의해 빈번하게 갱신되기 때문에 뮤택스로 보호된다.

2.3 프리 리스트

프리 리스트는 사용하지 않는 페이지를 추적하고 관리하기 위해 사용된다.

3. 버퍼 풀 플러시

InnoDB 버퍼 풀은 더티 페이지를 모아 두었다가 한 번에 디스크에 동기화하는 작업인 플러시를 백그라운드에서 수행함으로써 사용자의 쿼리 처리에 영향을 주지 않으며 쓰기 버퍼링 기능을 지원한다. InnoDB는 다음의 2가지 플러시를 페이지 클리너(Page Cleaner)라는 백그라운드 쓰레드가 수행한다. 페이지 클리너 개수는 innodb_page_cleaners로 설정할 수 있으며 기본적으로 버퍼 풀 인스턴스 개수만큼 있다. 이를 더 적게 설정하게 되면 하나의 페이지 클리너가 여러 개의 버퍼 풀 인스턴스를 처리한다.

3.1 LRU 리스트 플러시

주기적으로 페이지 클리너가 LRU 리스트에서 사용 빈도가 낮은 데이터 페이지들을 제거해 메모리 공간을 확보한다. 페이지 클리너가 각 버퍼 풀 인스턴스마다 LRU 리스트의 끝 부분부터 innodb_lru_scan_depth 만큼 탐색하면서 더티 페이지는 플러시를 수행하고, 클린 페이지는 즉시 프리 리스트로 옮긴다.

3.2 플러시 리스트 플러시

버퍼 풀에 더티 페이지의 비율이 innodb_max_dirty_pages_pct_lwm(기본값 10%)가 되면 버퍼 풀 플러시가 발생하는데, 이는 버퍼 풀의 더티 페이지 비율을 조절하고 innodb_max_dirty_pages_pct(기본값 90%)까지 되지 않기 위해 방지하기 위함이다. 만약 더티 페이지의 비율이 innodb_max_dirty_pages_pct가 되면 InnoDB가 버퍼 풀 플러시를 강제로 수행한다. 데이터 페이지 비율이 innodb_max_dirty_pages_pct가 됐을때 한 번에 수행하지 않고 조금씩 플러시를 하는 이유는 한 번에 많은 더티 페이지를 플러시하게 되면 쓰기 폭발 현상이 발생할 수 있기 때문이다. 쓰기 폭발이 발생하면 InnoDB의 일반적인 읽기/쓰기 성능에 영향이 갈 수 있다. 이를 방지하기 위해 InnoDB는 더티 페이지의 생성 속도와 현재 플러시 비율을 분석해서 동적으로 적절하게 플러시를 수행하는 어댑티브 플러시(Adaptive flush)라는 기능을 제공한다.

참고 자료

profile
느려도 조금씩 꾸준하게

0개의 댓글