본문 바로가기
MariaDB

MariaDB innodb_buffer_pool_size 사이징과 재시작 후 캐시 워밍업

열린기술자·2026년 8월 9일·조회 1

InnoDB로 돌아가는 MariaDB 서버를 넘겨받으면 가장 먼저 확인하는 값 중 하나가 innodb_buffer_pool_size다. 물리메모리 64GB짜리 장비인데 이 값이 기본값 그대로 128MB로 남아 있는 경우를 현장에서 드물지 않게 만난다. 재시작 직후 한동안 쿼리가 느려진다는 문의도 결국 여기서 갈리는 일이 많다. 이 글은 버퍼 풀을 워크로드에 맞게 잡고, 재시작 뒤 캐시가 다시 데워질 때까지의 지연을 없애는 방법을 순서대로 정리한 것이다.

요약: 전용 DB 서버라면 innodb_buffer_pool_size를 물리메모리의 60~75% 선에서 잡되 데이터 총량을 넘길 필요는 없다. 버퍼 풀이 충분한지는 Innodb_buffer_pool_reads(디스크 물리 읽기)와 Innodb_buffer_pool_read_requests(논리 읽기 요청)의 비율로 판단한다. 재시작 콜드 스타트는 innodb_buffer_pool_dump_at_shutdowninnodb_buffer_pool_load_at_startup으로 버퍼 풀 내용을 파일에 저장했다가 되살려 없앤다.

1. 버퍼 풀이 무엇이고 왜 크기가 중요한가

InnoDB 버퍼 풀은 자주 읽는 데이터 페이지와 인덱스 페이지를 메모리에 올려 두는 캐시다. 쿼리가 필요한 페이지가 버퍼 풀에 있으면 디스크를 건드리지 않고 메모리에서 바로 읽는다. 없으면 디스크에서 페이지를 읽어와 버퍼 풀에 채운다. 그래서 버퍼 풀이 작으면 같은 데이터를 반복해서 디스크에서 읽게 되고, 이것이 곧 응답 지연으로 이어진다.

버퍼 풀은 LRU(Least Recently Used) 기반으로 오래 안 쓴 페이지부터 밀어낸다. 내부적으로 최근 사용 페이지를 담는 new 서브리스트와 오래된 페이지를 담는 old 서브리스트로 나뉘어 동작한다. 이 구조 덕분에 대량 스캔이 한 번 훑고 지나가도 자주 쓰는 페이지가 곧바로 밀려나지 않는다.

Oracle을 다뤄 본 독자라면 이 버퍼 풀을 Oracle의 버퍼 캐시(Database Buffer Cache, SGA의 일부)에 대응시켜 이해하면 편하다. 역할은 같고, 크기를 하나의 변수로 명시적으로 잡는다는 점이 다르다.

2. 환경과 현재 설정 확인

기준 환경은 MariaDB 10.11 LTS, RHEL 9 호환 리눅스, 전용 DB 서버(다른 서비스가 같은 장비를 안 쓴다)로 둔다. 버전 번호와 출력값은 서버 상태에 따라 다를 수 있다.

$ mariadb --version
mariadb from 10.11.x-MariaDB, client ...

MariaDB [(none)]> SELECT @@version, @@innodb_buffer_pool_size/1024/1024 AS pool_mb;
+-----------------+---------+
| @@version       | pool_mb |
+-----------------+---------+
| 10.11.x-MariaDB | 128.000 |
+-----------------+---------+

128MB로 나오면 기본값이다. 공식 문서 기준 innodb_buffer_pool_size의 기본값은 134217728바이트, 즉 128MiB다. 운영 DB에서 이 값이 그대로면 사이징이 안 된 상태로 본다.

물리메모리도 같이 확인한다.

$ free -h
               total        used        free      shared  buff/cache   available
Mem:            62Gi        4.2Gi        50Gi       1.0Mi        8.1Gi        57Gi
Swap:          2.0Gi          0B        2.0Gi

3. 물리메모리 대비 비율 산정

전용 DB 서버에서 출발점은 물리메모리의 60~75%다. 나머지는 MariaDB의 다른 버퍼(스레드별 버퍼, 정렬 버퍼 등)와 OS 페이지 캐시, 커넥션 수에 따른 메모리에 남겨 둔다. 64GB 장비라면 대략 40~48GB 사이에서 시작한다.

다만 비율은 상한을 정하는 규칙일 뿐이다. 실제 데이터와 인덱스 총량이 30GB인데 물리메모리가 128GB라면, 버퍼 풀을 90GB까지 키울 이유가 없다. 데이터 총량을 조금 웃도는 선이면 워킹셋 대부분이 메모리에 상주한다. 데이터 크기부터 확인한다.

MariaDB [(none)]> SELECT ROUND(SUM(data_length+index_length)/1024/1024/1024,1) AS total_gb
    -> FROM information_schema.tables
    -> WHERE engine='InnoDB';
+----------+
| total_gb |
+----------+
|     28.6 |
+----------+

정리하면 이렇게 잡는다. 데이터 총량이 물리메모리보다 크면 물리메모리의 60~75%를 쓴다. 데이터 총량이 물리메모리보다 작으면 데이터 총량에 인덱스 증가와 여유분을 더한 값(대략 데이터 총량의 1.2~1.5배)과 위 60~75% 상한 중 작은 쪽을 쓴다. 위 예시(데이터 28.6GB, 메모리 62GB)라면 40GB 안팎이 무난하다.

버퍼 풀 인스턴스를 나누는 innodb_buffer_pool_instances는 신경 쓰지 않아도 된다. MariaDB 10.5.1부터 이 변수는 무시되고 버퍼 풀은 크기와 무관하게 단일 인스턴스로 동작한다. 예전 튜닝 글에서 인스턴스를 8개로 쪼개라는 조언을 봤다면 지금 버전에는 해당하지 않는다.

4. 값 적용 - 런타임 변경과 설정 파일

innodb_buffer_pool_size는 동적 변수다. 재시작 없이 런타임에 바꿀 수 있다. 급한 상황에서는 세션에서 바로 늘린다.

MariaDB [(none)]> SET GLOBAL innodb_buffer_pool_size = 40 * 1024 * 1024 * 1024;
Query OK, 0 rows affected (0.00 sec)

런타임 리사이즈는 즉시 끝나지 않고 백그라운드로 진행된다. 크기를 크게 늘리면 그동안 약간의 부하가 생길 수 있으니 트래픽이 몰리는 시간대는 피한다. 진행 상태는 리사이즈 관련 상태 변수로 확인할 수 있는데, 이 상태 변수는 최근 버전에서 정리되어 버전별로 노출이 다르다.

런타임 변경은 재시작하면 사라진다. 영구 적용은 설정 파일에 반드시 같이 넣는다. RHEL 계열은 /etc/my.cnf.d/server.cnf[mariadbd](구버전은 [mysqld]) 섹션에 적는다.

[mariadbd]
innodb_buffer_pool_size = 40G

여기서 한 번 걸리기 쉽다. 런타임으로만 늘려 놓고 설정 파일에 안 적으면, 다음 재시작 때 조용히 128MB로 되돌아간다. 값을 바꿨으면 설정 파일 반영을 항상 짝으로 처리한다.

5. Buffer pool hit ratio 측정

버퍼 풀이 충분한지는 감이 아니라 상태 변수로 판단한다. 핵심은 두 가지다. Innodb_buffer_pool_read_requests는 버퍼 풀에 대한 전체 논리 읽기 요청 수이고, Innodb_buffer_pool_reads는 버퍼 풀에 없어서 디스크에서 물리적으로 읽어야 했던 횟수다.

MariaDB [(none)]> SHOW GLOBAL STATUS WHERE Variable_name IN
    -> ('Innodb_buffer_pool_read_requests','Innodb_buffer_pool_reads');
+----------------------------------+-------------+
| Variable_name                    | Value       |
+----------------------------------+-------------+
| Innodb_buffer_pool_read_requests | 9823451120  |
| Innodb_buffer_pool_reads         | 4192233     |
+----------------------------------+-------------+

hit ratio는 다음과 같이 계산한다.

hit ratio = (1 - Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests) * 100
         = (1 - 4192233 / 9823451120) * 100
         = 99.96 %

여기서 한 가지 주의할 점이 있다. 이 두 값은 서버 기동 이후 누적치다. 누적 비율은 오래 켜 둔 서버일수록 100%에 붙어 있어서 지금 상태를 잘 못 보여준다. 진짜로 봐야 할 것은 증분이다. 공식 문서도 일정 시간 동안 Innodb_buffer_pool_reads 증가분이 Innodb_buffer_pool_read_requests 증가분의 1% 미만이면 건강한 상태로 본다고 설명한다.

증분을 보려면 두 시점의 값을 빼서 계산한다. 예를 들어 60초 간격으로 두 번 찍어 차이를 낸다.

MariaDB [(none)]> SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read%';
-- 60초 대기 후 다시 실행
-- delta_reads / delta_read_requests 가 0.01(1%) 미만이면 여유 있음

증분 비율이 1%를 넘고 Innodb_buffer_pool_wait_free가 계속 증가한다면 버퍼 풀이 워킹셋을 못 담고 있다는 신호다. 이때 3절로 돌아가 크기를 다시 올린다.

6. dump/load로 콜드 스타트 지연 없애기

버퍼 풀을 잘 잡아도 서버를 재시작하면 버퍼 풀이 텅 빈 상태로 시작한다. 이 상태에서는 모든 페이지를 디스크에서 다시 읽어 채워야 해서, 캐시가 데워질 때까지 한동안 쿼리가 느리다. 이것이 콜드 스타트다. 40GB 버퍼 풀이 자연스럽게 데워지려면 실제 트래픽으로 페이지가 다시 올라올 때까지 기다려야 한다.

InnoDB는 이 문제를 위해 버퍼 풀에 어떤 페이지가 올라와 있었는지 목록을 파일로 저장했다가, 재시작 후 그 목록대로 페이지를 미리 읽어 두는 기능을 제공한다. MariaDB에서는 두 변수가 기본적으로 켜져 있다. innodb_buffer_pool_dump_at_shutdown은 종료 시 페이지 목록을 저장하고(기본값 ON, 동적), innodb_buffer_pool_load_at_startup은 기동 시 그 목록을 읽어 버퍼 풀을 미리 채운다(기본값 ON, 재시작 필요).

저장 파일 이름은 innodb_buffer_pool_filename이며 기본값은 ib_buffer_pool다. 데이터 디렉터리에 생긴다.

MariaDB [(none)]> SHOW VARIABLES LIKE 'innodb_buffer_pool_dump_at_shutdown';
+-------------------------------------+-------+
| Variable_name                       | Value |
+-------------------------------------+-------+
| innodb_buffer_pool_dump_at_shutdown | ON    |
+-------------------------------------+-------+

$ ls -l /var/lib/mysql/ib_buffer_pool
-rw-rw---- 1 mysql mysql 512345 Aug  9 10:12 /var/lib/mysql/ib_buffer_pool

이 파일은 페이지 데이터 자체가 아니라 페이지 식별자(테이블스페이스ID와 페이지번호) 목록이라 크기가 작다. 그래서 종료가 오래 걸리지 않는다.

전체 페이지를 다 저장할 필요가 없으면 innodb_buffer_pool_dump_pct로 가장 최근에 쓰인 페이지의 상위 비율만 저장할 수 있다. 기본값은 25로, 최근 사용된 상위 25%만 저장한다. 재시작 후 워밍업을 더 확실히 하고 싶으면 이 값을 올린다.

[mariadbd]
innodb_buffer_pool_dump_at_shutdown = ON
innodb_buffer_pool_load_at_startup  = ON
innodb_buffer_pool_dump_pct         = 75

7. 재시작 없이 즉시 dump / load 하기

계획된 재시작 전에 수동으로 버퍼 풀 상태를 저장하고 싶으면 트리거 변수를 쓴다. innodb_buffer_pool_dump_now를 ON으로 세팅하면 즉시 파일로 저장한다. 이 변수는 트리거라서 실행 후 값은 다시 OFF로 돌아온다.

MariaDB [(none)]> SET GLOBAL innodb_buffer_pool_dump_now = ON;
Query OK, 0 rows affected (0.01 sec)

MariaDB [(none)]> SHOW STATUS LIKE 'Innodb_buffer_pool_dump_status';
+-------------------------------+--------------------------------------------------+
| Variable_name                 | Value                                            |
+-------------------------------+--------------------------------------------------+
| Innodb_buffer_pool_dump_status| Buffer pool(s) dump completed at 260809 10:20:31 |
+-------------------------------+--------------------------------------------------+

반대로 저장된 파일에서 지금 바로 버퍼 풀을 채우려면 innodb_buffer_pool_load_now를 ON으로 둔다. 진행 상태는 Innodb_buffer_pool_load_status로 본다.

MariaDB [(none)]> SET GLOBAL innodb_buffer_pool_load_now = ON;

MariaDB [(none)]> SHOW STATUS LIKE 'Innodb_buffer_pool_load_status';
+-------------------------------+----------------------------------------------------+
| Variable_name                 | Value                                              |
+-------------------------------+----------------------------------------------------+
| Innodb_buffer_pool_load_status| Buffer pool(s) load completed at 260809 10:21:05   |
+-------------------------------+----------------------------------------------------+

로드가 너무 오래 걸려 취소하고 싶으면 innodb_buffer_pool_load_abort를 ON으로 세팅한다.

8. 검증 순서

적용이 끝나면 다음을 차례로 확인한다. 첫째, 프로세스와 접속을 확인한다.

$ systemctl status mariadb --no-pager
$ mariadb -e "SELECT 1"

둘째, 버퍼 풀 크기가 의도한 값으로 올라왔는지 본다. 앞서 3~4절에서 잡은 값과 일치해야 한다.

MariaDB [(none)]> SELECT @@innodb_buffer_pool_size/1024/1024/1024 AS pool_gb;
+---------+
| pool_gb |
+---------+
| 40.0000 |
+---------+

셋째, 재시작 후 로드가 정상 완료됐는지 Innodb_buffer_pool_load_status로 확인한다. "load completed"가 나오면 콜드 스타트 대응이 끝난 것이다. 넷째, 하루 정도 운영한 뒤 5절의 증분 hit ratio를 다시 측정해 워킹셋이 버퍼 풀에 상주하는지 재확인한다.

9. 결론

전용 MariaDB 서버에서 버퍼 풀은 물리메모리의 60~75%와 데이터 총량 기준 중 작은 쪽으로 잡고, 값을 바꿨으면 설정 파일에도 반드시 반영해 재시작 때 되돌아가지 않게 한다. 충분한지는 누적치가 아니라 증분 hit ratio로 판단한다. 재시작 지연은 기본으로 켜져 있는 dump/load에 innodb_buffer_pool_dump_pct만 워크로드에 맞게 올려 두면 대부분 해결된다. 계획된 재시작 앞에서는 innodb_buffer_pool_dump_now로 최신 상태를 한 번 저장해 두면 안전하다.

자주 묻는 질문

innodb_buffer_pool_size는 물리메모리의 몇 %가 적절한가?

다른 서비스가 없는 전용 DB 서버라면 물리메모리의 60~75%가 출발점이다. 다만 데이터와 인덱스 총량이 물리메모리보다 작으면 총량을 조금 웃도는 값(대략 총량의 1.2~1.5배)과 60~75% 상한 중 작은 쪽을 쓴다. 나머지는 다른 버퍼와 OS 페이지 캐시, 커넥션에 남긴다.

innodb_buffer_pool_size를 재시작 없이 바꿀 수 있나?

된다. 동적 변수라 SET GLOBAL innodb_buffer_pool_size = ... 로 런타임에 바꾼다. 리사이즈는 백그라운드로 진행되며 크게 늘릴 때 약간의 부하가 생길 수 있다. 단 런타임 변경은 재시작하면 사라지므로 설정 파일에도 같은 값을 반드시 적어야 한다.

버퍼 풀 hit ratio는 어떻게 계산하나?

(1 - Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests) * 100 으로 구한다. 두 값은 기동 이후 누적치라 오래 켜 둔 서버는 항상 100%에 가깝다. 실제 상태는 두 시점의 차이를 낸 증분으로 판단하며, reads 증가분이 read_requests 증가분의 1% 미만이면 여유 있는 상태로 본다.

재시작 후 캐시 워밍업 지연을 없애려면?

MariaDB는 innodb_buffer_pool_dump_at_shutdown(기본 ON)으로 종료 시 페이지 목록을 저장하고 innodb_buffer_pool_load_at_startup(기본 ON)으로 기동 시 되살린다. 둘 다 기본 활성이므로, 워밍업을 더 확실히 하려면 innodb_buffer_pool_dump_pct(기본 25)를 75 정도로 올린다.

innodb_buffer_pool_instances를 몇 개로 나눠야 하나?

MariaDB 10.5.1부터 이 변수는 무시되고 버퍼 풀은 크기와 무관하게 단일 인스턴스로 동작한다. 예전 버전 튜닝 글의 인스턴스 분할 조언은 현재 버전에는 적용되지 않는다. 신경 쓸 필요가 없다.

관련 글

댓글 0

로그인 후 댓글을 남길 수 있습니다.

아직 댓글이 없습니다.