기존의 Real MySQL (5.0, 5.1 버전) 책을 너무 유익하게 봤는데, Real MySQL 8.0이 전면 개정판이 나와서... 설레는 마음에 보면서 개인적인 공부용으로 정리하고 있습니다.
역시 믿고 보는 Real MySQL... 👍 한번 사서 보시는 것을 강력 추천드립니다!
MySQL 데이터 압축
MySQL 서버에서 디스크에 저장된 데이터 파일의 크기는 일반적으로 쿼리의 처리 성능과도 직결되지만 백업 및 복구 시간과도 밀접하게 연결된다
이러한 문제점을 해결하기 위해 데이터 압축 기능을 제공한다. MySQL 서버에서 사용 가능한 압축 방식은 크게 테이블 압축과 페이지 압축을 제공한다.
페이지 압축
MySQL 서버가 디스크에 저장하는 시점에 데이터 페이지가 압축되어 저장되고, 반대로 MySQL 서버가 디스크에서 데이터 페이지를 읽어올 때 압축이 해제되기 때문이다. 그래서 MySQL 서버의 내부 코드에서는 압축 여부와 관계없이 투명하게 작동한다.
- 여기서 한 가지 문제점이 있는데, 16KB 데이터 페이지를 압축한 결과가 요량이 얼마나 될지 예측이 불가능한데 적어도 하나의 테이블은 동일한 크기의 블록으로 통일돼야 한다는 것이다.
그래서 페이지 압축 기능은 운영체제별로 특정 버전의 파일 시스템에서만 지원되는 펀치 홀이라는 기능을 사용한다.
페이지 압축 작동 방식
- 16KB 페이지를 압축 (압축 결과를 7KB로 가정)
- MySQL 서버는 디스크에 압축된 결과 7KB를 기록 (이때 MySQL 서버는 압축 데이터 7KB에 9KB의 빈 데이터를 기록)
- 디스크에 데이터를 기록한 후, 7KB 이후의 공간 9KB에 대해 펀치 홀을 생성
- 파일 시스템은 7KB만 남기고 나머지 디스크의 9KB 공간은 다시 운영체제로 반납.
(실제 디스크의 공간은 7KB만 차지하지만, 운영체제에서 16KB를 읽으면 압축된 데이터 7KB와 펀치 홀 공간인 9KB를 합쳐서 16KB를 읽는다)
문제점
- 펀치 홀 기능은 운영체제뿐만 아니라 하드웨어 자체에서도 해당 기능을 지원해야 사용 가능한다는 점.
- 아직 파일 시스템 관련 명령어가 펀치 홀을 지원하지 못한다는 것.
- 이러한 이유로 실제 페이지 압축은 많이 사용되지 않는 상태이다.
테이블 압축
테이블 압축은 운영체제나 하드웨어에 대한 제약 없이 사용할 수 있기 때문에 일반적으로 더 활용도가 높은 편이다.
- 테이블 압축은 우선 디스크의 데이터 파일 크기를 줄일 수 있기 때문에 그만큼의 이득은 있다.
- 버퍼 풀 공간 활용률이 낮음
- 쿼리 처리 성능이 낮음
- 빈번한 데이터 변경 시 압축률이 떨어짐.
압축 테이블 생성
테이블 압축을 사용하기 위한 전제 조건으로 압축을 사용하려는 테이블이 별도의 테이블 스페이스를 사용해야 한다. 이를 위해서는 innodb_file_per_table 시스템 변수가 ON으로 설정된 상태에서 테이블이 생성되어야 한다.
이제 테이블 압축을 사용하는 테이블은 ROW_FORMAT=COMPRESSED 옵션을 명시해야 한다.
- 추가로 KEY_BLOCK_SIZE 옵션을 이용해 압축된 페이지의 타깃 크기를 명시하는데, 2n으로만 설정할 수 있다. (InnoDB 스토리지 엔진의 페이지 크기가 16KB라면 KEY_BLOCK_SIZE는 4KB 또는 8KB만 설정할 수 있다, 또한 페이지 크기가 32KB 또는 64KB인 경우에는 테이블 압축을 적용할 수 없다)
SET GLOBAL innodb_file_per_table=ON;
CREATE TABLE compressed_table (
...
)
ROW_FORMAT=COMPRESSED
KEY_BLOCK_SIZE=8;
압축 적용에 사용되는 KEY_BLOCK_SIZE 옵션은 압축된 페이지가 저장될 페이지의 크기를 지정한다.
테이블 압축 동작 방식
예를 들어 InnoDB 스토리지 엔진의 데이터 페이지 블록 크기가 16KB, KEY_BLOCK_SIZE가 8로 설정되었다고 가정하면
- 16KB의 데이터 페이지를 압축
- 압축된 결과가 8KB 이하이면 그대로 디스크에 저장 (압축 완료)
- 8KB를 초과하면 원본 페이지를 스플릿해서 2개의 페이지에 8KB씩 저장
- 나뉜 페이지 각각에 1번 단계를 반복 실행.
테이블 압축에서 가장 중요한 것은 원본 데이터 페이지의 압축 결과가 목표 크기보다 작거나 같을 때까지 반복해서 페이지를 스플릿 하는 것이다. 그래서 목표 크기가 잘못 설정되면 MySQL 서버의 처리 성능이 급격히 떨어질 수 있으니 주의해야 한다.
KEY_BLOCK_SIZE 결정
테이블 압축에서 가장 중요한 부분은 압축된 결과가 어느 정도가 될지를 예측해서 KEY_BLOCK_SIZE를 결정하는 것이다. 그래서 테이블 압축을 적용하기 전에 먼저 KEY_BLOCK_SIZE를 4KB 또는 8KB로 테이블을 생성해서 샘플 데이터를 저장해 보고 적절한지 판단하는 것이 좋다.
압축된 페이지와 버퍼 풀 적재 및 사용
InnoDB 스토리지 엔진은 압축된 테이블의 데이터 페이지를 버퍼 풀에 적재하면 압축된 상태와 압축이 해제된 상태 2개 버전을 관리한다.
그래서 InnoDB 스토리지 엔진은 디스크에서 읽은 상태 그래도의 데이터 페이지 목록을 관리하는 LRU 리스트와 압축된 페이지들의 압축 해제 버전인 Unzip_LRU 리스트를 별도로 관리하게 된다.
MySQL 서버에는 압축된 테이블과 압축되지 않은 테이블이 공존하므로 결국 LRU 리스트는 다음과 같이 압축된 페이지와 압축되지 않은 페이지를 모두 가질 수 있다.
- 압축이 적용되지 않은 테이블의 데이터 페이지
- 압축이 적용된 테이블의 압축된 데이터 페이지
Unzip_LRU 리스트는 압축이 적용되지 않은 테이블의 데이터 페이지는 가지지 않으며, 압축이 적용된 테이블에서 읽은 데이터 페이지만 관리한다. 물론 Unzip_LRU 리스트에는 압축을 해제한 상태의 데이터 페이지 목록이 관리된다.
한계점
- 결국 InnoDB 스토리지 엔진은 압축된 테이블에 대해서는 버퍼 풀의 공간을 이중으로 사용함으로써 메모리를 낭비하는 효과를 가진다. 또 다른 문제점으로는 압축된 페이지에서 데이터를 읽거나 변경하기 위해서는 압축을 해제해야 한다는 것인데, 압축 및 압축 해제 작업은 CPU를 상대적으로 많이 소모하는 작업이다.
이러한 두 가지 단점을 보완하기 위해 Unzip_LRU 리스트를 별도로 관리하고 있다가 MySQL 서버로 유입되는 요청 패턴에 따라 적절히 다음과 같은 처리를 수행한다.
- InnoDB 버퍼 풀의 공간이 필요한 경우에는 LRU 리스트에서 원본 데이터 페이지는 유지하고, Unzip_LRU 리스트에서 압축 해제된 버전은 제거해서 버퍼 풀의 공간을 확보한다.
- 압축된 데이터 페이지가 자주 사용되는 경우에는 Unzip_LRU 리스트에 압축 해제된 페이지를 계속 유지하면서 압축 및 압축 해제 작업을 최소화한다.
- 압축된 데이터 페이지가 사용되지 않아서 LRU 리스트에서 제거되는 경우에는 Unzip_LRU 리스트에서도 함께 제거된다.
InnoDB 스토리지 엔진은 버퍼 풀에서 압축 해제된 버전의 데이터 페이지를 적절한 수준으로 유지하기 위해 다음과 같은 어댑티브 알고리즘을 사용한다.
- CPU 사용량이 높은 서버에서는 가능하면 압축과 압축 해제를 피하기 위해 Unzip_LRU의 비율을 높여서 유지
- Disk I/O 사용량이 높은 서버에서는 가능하면 Unzip_LRU 리스트의 비율을 낮춰서 InnoDB 버퍼 풀의 공간을 더 확보하도록 작동한다.
'DBMS > MySQL' 카테고리의 다른 글
[MySQL] B-Tree 인덱스 (0) | 2021.09.13 |
---|---|
[MySQL] 인덱스 (0) | 2021.09.13 |
[MySQL] 잠금 (0) | 2021.09.12 |
[MySQL] InnoDB 스토리지 엔진 아키텍처 (0) | 2021.09.10 |
[MySQL] MySQL엔진 아키텍처 (0) | 2021.09.08 |