운영체제 전체 메모리 공간이 8GB 미만인 경우 50% 정도만 InnoDB 버퍼 풀로 설정하고 나머지 메모리 공간은 MySQL 서버와 운영체제, 그리고 다른 프로그램들이 사용할 수 있는 공간으로 확보해주는 것이 좋다.
운영체제 전체 메모리 공간이 8GB 이상 50G 미만인 경우 버퍼 풀의 크기를 전체 메모리의 50%에서 시작해서 조금씩 올려가면서 최적점을 찾는다.
운영체제 전체 메모리 공간이 50GB 이상인 경우 15GB ~ 30GB 정도만 남겨두고 나머지를 버퍼 풀로 할당하자.
-ppt-
3. 버퍼 풀의 구조
InnoDB 스토리지 엔진은 버퍼 풀이라는 메모리 공간을
페이지 크기 (innodb_page_size 시스템 변수에 설정된) 조각으로 쪼개어,
InnoDB 스토리지 엔진이 데이터를 필요로 할 때
해당 데이터 페이지를 디스크로부터 읽어와서 각 조각에 저장한다.
InnoDB 스토리지 엔진은 버퍼풀의 페이지들을 관리하기 위해 다음 세개의 자료구조를 관리한다.
Free list 데이터로 채워지지 않은, 비어있는 페이지들의 목록
LRU list 데이터로 채워져있는 페이지들의 목록
Flush list 변경이 가해진 페이지들의 목록
4. LRU List
데이터가 채워져있는 페이지들의 목록이다.
버퍼 풀이라는 캐시 공간은 한정되어있기 때문에
다시 쓰일 가능성이 높은 데이터 페이지들을 위주로 캐싱하는 것이 효과적이다.
그래서 자주 안쓰이는 페이지들을 제거하고 자주 쓰이는 페이지를 메모리에 상주시키기 위해 다음과 같은 알고리즘을 사용한다.
처음으로 디스크에서 읽힌 페이지는 일단 Old 서브리스트의 head 부분에 붙는다.
버퍼 풀에 있던 데이터가 재사용되면 해당 페이지는 위쪽 방향으로 승급한다.
캐시 공간 마련을 위해 페이지들을 지울 때, 리스트 아래(Old 서브리스트 tail 부분)부터 차례대로 지운다.
따라서
버퍼 풀에 올라온 어떤 데이터 페이지가
자주 사용되면 New 서브리스트 영역에서 계속 살아남고,
반대로 거의 사용되지 않는다면
새롭게 디스크에서 읽히는 데이터 페이지들에 밀려서
Old 서브리스트의 끝으로 밀려나 결국은 버퍼풀에서 제거된다.
5. 리두 로그 파일
리두 로그 파일은 고정 크기의 파일이다.
InnoDB 스토리지 엔진은 데이터 변경 시 다음 세가지 작업을 한다.
1. 버퍼풀의 페이지에 변경 내용을 반영
2. 리두 로그 파일에도 변경 내용을 저장
3. 변경된 페이지를 flush list가 참조함
리두 로그는 왜 필요할까?
만약 MySQL 서버가 쓰기 지연을 하고있었는데 다운되었다고 해보자.
메모리에 있는 버퍼풀 쓰기지연 데이터가 날아가버려도, 리두로그는 디스크에 남아있으므로 복구할 수 있다. 2)
-ppt-
6. 버퍼 풀과 리두 로그
리두로그는 1개 이상의 고정 크기 파일을 연결해서 순환 고리처럼 사용한다.
즉, 데이터 변경이 계속 발생하면 덮어쓰인다.
그래서 재사용 가능한 공간과 당장 재사용 불가능한 공간을 구분해서 관리해야한다.
재사용 불가능한 공간을 활성 리두 로그라 한다.
리두 로그 파일의 공간은 계속 순환되어 재사용되지만
매번 기록될 때마다 로그 포지션은 계속 증가된 값을 갖게되는데, 이를 LSN(Log Sequence Number 라고 한다.
체크 포인트
리두 로그와 버퍼 풀의 더티 페이지를 디스크로 동기화하는 이벤트.
InnoDB 스토리지 엔진은 주기적으로 체크포인트 이벤트를 발생시킨다.
체크 포인트 에이지
활성 리두 로그 공간의 크기
리두 로그 크기 정하기
* 리두 로그 크기가 너무 작을 경우
모든 더티 페이지는 리두 로그로 관리되어야 한다.
따라서 버퍼 풀의 크기가 크더라도 리두 로그 크기가 너무 작으면 쓰기 버퍼링 효과는 거의 보지 못한다.
* 리두 로그 크기가 너무 클 경우
이 경우 이론적으로는 문제가 없어보이지만
서비스를 운영하다 보면 급작스러운 디스크 쓰기가 발생할 가능성이 높다.
버퍼 풀에 더티 페이지의 비율이 너무 높은 상태에서 갑자기 버퍼 풀이 필요해지는 상황이 오면
InnoDB 스토리지 엔진이 매우 많은 더티 페이지를 한번에 기록해야 하는 상황이 온다.
* 책에서 제안하는 방법
버퍼 풀의 크기가 100GB 이하인 MySQL 서버에서는
리두 로그 파일의 전체 크기를 대략 5~10GB 수준으로 선택하고
필요할 때마다 조금씩 늘려가면서 최적값을 선택하는 것이 좋다.
리두 로그는 변경분만 가지고 있고 버퍼풀을 변경된적 없는 페이지들도 가지고 있기 때문에
리두 로그는 버퍼풀의 크기보다 훨씬 작은 공간만 있으면 된다.
7. 버퍼 풀 플러시
MySQL 8.0 버전 이후부터는 더티 페이지를 디스크로 동기화할 때 디스크 폭증 현상이 발생하지 않는다.
따라서 특별히 성능 문제가 발생하지 않는한 디스크 쓰기 동기화 시스템 변수들을 조정할 필요는 없다.
InnoDB 스토리지 엔진은 더티 페이지들을 성능상의 악영향 없이 디스크에 동기화하기 위해 다음 2개의 플러시 기능을 백그라운드로 실행한다.
Flush_List 플러시
LRU_List 플러시
7.1 Flush_List 플러시
InnoDB는 Flush_List 플러시 함수를 주기적으로 호출해서 더티페이지들을 디스크에 동기화한다.
변경된지 오래된 더티 페이지부터 순서대로 작업한다.
7.2 LRU_List 플러시
InnoDB 스토리지 엔진은 LRU 리스트에서 사용 빈도가 낮은 데이터 페이지들을 제거해서
새로운 페이지들을 읽어올 공간을 만들어야 하는데, 이를 위해 LRU_list 플러시 함수가 사용된다.
클린 페이지 : 즉시 Free 리스트로 옮김
더티 페이지 : 디스크에 동기화 한 다음 Free 리스트로 옮김
8. 버퍼 풀 상태 백업 및 복구
디스크의 데이터가 버퍼 풀에 적재돼 있는 상태를 워밍업(Warming UP)이라고 표현한다.
버퍼 풀이 잘 워밍업 된 상태에서는 그렇지 않은 경우보다 몇십 배의 쿼리 처리 속도를 보이는 것이 일반적이다.
그래서 서버 점검 등의 이유로 서버를 재시작할 때 버퍼풀을 복구할 수 있도록, MySQL 에서는 버퍼풀 백업 및 복구 기능을 제공한다.
-- MySQL 서버 셧다운 전에 버퍼 풀의 상태 백업
mysql> SET GLOBAL innodb_buffer_pool_dump_now=ON
-- MySQL 서버 재시작 후, 백업된 버퍼 풀의 상태 복구
mysql> SET GLOBAL innodb_buffer_pool_load_now=ON
버퍼 풀 백업은 메타 정보를 백업하는 것이기 때문에 백업은 매우 빠르고 백업 파일 크기도 매우 작다.
버퍼 풀 복구는 백업해둔 메타정보를 바탕으로 디스크에서 읽어와서 버퍼풀에 적재하기 때문에 시간이 많이 걸릴 수도 있다.
참고
1
Real MySQL 8.0 (백은빈, 이성욱)
2
Managing the Redo Log
일부 인용 : "Redo entries record data that you can use to reconstruct all changes made to the database, including the undo segments. Therefore, the redo log also protects rollback data. When you recover the database using redo data, the database reads the change vectors in the redo records and applies the changes to the relevant blocks."