책너두 (Real MySQL 8.0 1권) 17일차 (~194p)
- Book/Real Mysql 8.0
- 2023. 1. 22.
현재 책너두 1.5기 모집 링크 입니다 : https://breakbook.notion.site
요약
- MySQL 의 데이터 압축 방식 및 프로세스를 이해하게됨.
- 페이지 압축에 대한 이해와 그 방식을 이해하게 됨.
- 테이블 압축에 대한 이해와 그 방식을 이해하게 됨.
- 생각보다 생소한 내용이여서 훑어보는 식으로 이해한 것같다.. 다시 읽어보거나 추가 레퍼런스를 읽으며 이해할 필요가 있음.
메모
데이터 압축
- MySQL 서버에서 디스크에 저장된 데이터 파일의 크기는 쿼리의 처리 성능과도 직결되지만 백업 & 복구 시간과도 밀접하게 연결됨.
- 데이터 파일이 크면 클수록 백업 시간이 오래 걸리며, 복구하는 데도 그만큼의 시간이 걸림
- 또 그만큼 저장 공간이 필요하므로 비용 문제도 발생함.
- 데이터 파일이 크면 클수록 백업 시간이 오래 걸리며, 복구하는 데도 그만큼의 시간이 걸림
- 디스크의 데이터 파일이 크면 클수록 쿼리를 처리하기 위해 더 많은 데이터 페이지를 InnoDB 버퍼 풀로 읽어야 할 수 있다.
- 새로운 페이지가 버퍼 풀로 적재 되기 때문에 그만큼 더티 페이지가 더 자주 디스크로 기록돼야 함.
- 위 문제를 해결하기 위해 DBMS 에서 데이터 압축 기능을 제공함.
- MySQL 서버에서 사용가능한 압축방식으로는
- 테이블 압축
- 페이지 압축
- 두 가지 종료로 구분함.
페이지 압축
- 페이지 압축은 “Transparent Page Compression” 이라고도 부름
- MySQL 서버가 디스크에 저장하는 시점에 데이터 페이지가 압축되어 저장됨.
- MySQL 서버가 디스크에서 데이터 페이지를 읽어올 때 압축이 해제됨.
- 즉, 버퍼 풀에 데이터 페이지가 한 번 적재되면 InnoDB 스토리지 엔진은 압축이 해제된 상태로만 데이터 페이지를 관리한다.
- 그래서 MySQL 서버의 내부 코드에서는 압축 여부와 관계없이 “투명(Transparent)” 하게 작동함.
- 문제점 : 16KB 데이터 페이지를 압축한 결과가 용량이 얼마나 될지 예측이 불가능함.
- 적어도 하나의 테이블은 동일한 크기의 페이지(블록)로 통일돼야 함. (이게 무슨 말 ..?)
- 페이지 압축 기능은 운영체제별로 특정 버전의 파일 시스템에서만 지원되는
펀치 홀(Punch hole)
이라는 기능을 사용함. - MySQL 서버는 특정 테이블에 대해 16KB 크기의 페이지를 유지하면서도 압축된 다양한 크기의 데이터 페이지를 디스크에 저장하고 압축된 만큼의 공간을 절약할 수 있다.
- 페이지 압축 기능은 운영체제별로 특정 버전의 파일 시스템에서만 지원되는
- 적어도 하나의 테이블은 동일한 크기의 페이지(블록)로 통일돼야 함. (이게 무슨 말 ..?)
- 운영체제(파일 시스템)의 블록 사이즈가 512바이트인 경우, 페이지 압축이 작동하는 방식은 다음과 같다.
- 16KB 페이지를 압축함. (압축 결과가 7KB 로 가정)
- MySQL 서버는 디스크에 압축된 결과인 7KB 를 기록함. (이때, MySQL 서버는 압축 데이터 7KB에 9KB의 빈 데이터를 기록한다.)
- 디스크에 데이터를 기록한 후, 7KB 이후의 공간 9KB에 대해 펀치 홀(Punch-hole)을 생성한다.
- 파일 시스템은 7KB만 남기고 나머지 디스크의 9KB 공간은 다시 운영체제로 반납한다.
- 위 그림의 오른쪽 상태에서 펀치 홀이 9KB 만큼 생성되면서 실제 디스크의 공간은 7KB만 차지한다.
- 하지만 운영체제에서는 16KB를 읽으면 압축된 데이터 7KB와 펀치 홀 공간인 9KB를 합쳐서 16KB를 읽음.
- MySQL 서버의 페이지 압축이 가진 문제는 펀치 홀 기능이 운영체제뿐만 아니라 하드웨어 자체에서도 해당 기능을 지원해야 사용가능하다는 점임.
- 또 다른 문제점으로 아직 파일 시스템 관련 명령어(유틸리티)가 펀치 홀을 지원하지 못한다는 것이다.
- MySQL 서버의 데이터 파일은 해당 서버에만 머무는 것이 아님.
- 데이터 파일을 백업했다가 복구하는 과정에서 데이터 파일 복사 과정이 실행되고 그 외에도 많은 파일 관련 유틸리티들을 사용한다.
- ex) 펀치 홀이 적용되어 실제 데이터 파일의 크기가 1GB 라고 하더라도 “cp” 와 같은 파일 복사 명령, 또는 XtraBackup 같은 툴이 파일을 복사하면 펀치 홀이 다시 채워져서 데이터 파일의 크기는 원본 크기인 10GB가 될 수도 있음.
- 데이터 파일을 백업했다가 복구하는 과정에서 데이터 파일 복사 과정이 실행되고 그 외에도 많은 파일 관련 유틸리티들을 사용한다.
- MySQL 서버의 데이터 파일은 해당 서버에만 머무는 것이 아님.
- 위와 같은 이유로 실제 페이지 압축은 많이 사용되지 않는 상태임.
- 페이지 압축을 이용하기 위해서는 테이블을 생성하거나 변경할 때 다음과 같이 COMPRESSION 옵션을 설정하면 된다.
// 테이블 생성 시
mysql> CREATE TABLE t1 (c1 INT) COMPRESSION="zlib";
// 테이블 변경 시
mysql> ALTER TABLE t1 COMPRESSION='zlib";
mysql> OPTIMIZE TABLE t1;
테이블 압축
- 테이블 압축은 운영체제나 하드웨어에 대한 제약 없이 사용할 수 있음.
- 일반적으로 더 활용도가 높음.
- 테이블 압축은 우선 디스크의 데이터 파일 크기를 줄일 수 있기 때문에 그만큼의 이득이 있음.
- 하지만 테이블 압축도 몇가지 단점이 있음.
- 버퍼 풀 공간 활용률이 낮음
- 쿼리 처리 성능이 낮음
- 빈번한 데이터 변경 시 압축률이 떨어짐.
- 이 단점을 발생하는 이유를 알기 위해서, 내부적으로 어떻게 압축이 실행되어 디스크에 저장되는지 이해해야함.
- 또, 압축된 데이터 페이지들이 버퍼 풀에 어떻게 적재되어 사용되는지 이해해야 함.
압축 테이블 생성
- 테이블 압축을 사용하기 위한 전제 조건
- 압축을 사용하려는 테이블이 별도의 테이블 스페이스를 사용해야 한다.
- 이를 위해,
innodb_file_per_table
시스템 변수가 ON 으로 설정된 상태에서 테이블이 생성돼야 함. - 그리고, 테이블 압축을 사용하는 테이블은 다음과 같이 테이블을 생성할 때 ROW_FORMAT=COMPRESSED 옵션을 명시해야 함.
- 추가로, KEY_BLOCK_SIZE 옵션을 이용해 압축된 페이지의 타깃 크기(목표 크기)를 명시해야 함.
- 2n(n > 1) 로만 설정할 수 있다.
- InnoDB 스토리지 엔진의 페이지 크기(
innodb_page_size
)가 16KB 라면 KEY_BLOCK_SIZE는 4KB 또는 8KB만 설정할 수 있다. - 그리고 페이지 크기가 32KB 또는 64KB인 경우에는 테이블 압축을 적용할 수 없다.
- 이를 위해,
- 압축을 사용하려는 테이블이 별도의 테이블 스페이스를 사용해야 한다.
mysql> SET GLOBAL innodb_file_per_table=ON;
// ROW_FORMAT 옵션과 KEY_BLOCK_SIZE 옵션을 모두 명시
mysql> CREATE TABLE compressed_table (
c1 INT PRIMARY KEY
)
ROW_FORMAT=COMPRESSED
KEY_BLOCK_SIZE=8;
// KEY_BLOCK_SIZE 옵션만 명시
mysql> CREATE TABLE compressed_table (
c1 INT PRIMARY KEY
)
KEY_BLOCK_SIZE=8;
- 두 번째 테이블 생성 구문처럼 ROW_FORMAT 옵션이 생략되면 자동으로 ROW_FORMAT=COMPRESSED 옵션이 추가되어 생성됨.
- KEY_BLOCK_SIZE 에 명시된 옵션관은 KB 단위로 설정된다.
innodb_file_per_table 시스템 변수가 0인 상태에서 제너럴 테이블스페이스(General Tablespzce)에 생성되는 테이블도 테이블 압축을 사용할 수 있다. 하지만 제너럴 테이블스페이스의 FILE_BLOCK_SIZE에 의해 압축을 사용할 수도 있고 그러지 못할 수도 있음. 제너럴 테이블스페이스를 사용하는 테이블에 대해 압축을 고려중이라면 먼저 매뉴얼의 제너럴 테이블스페이스 제약 사항을 검토해봐야 함.
- 압축 적용에 사용되는 KEY_BLOCK_SIZE 옵션은 압축된 페이지가 저장될 페이지의 크기를 지정한다.
- ex) 현재 InnoDB 스토리지 엔진읜 데이터 페이지(블록) 크기가 16KB 이고 KEY_BLOCK_SIZE가 8로 설정된 상황이라 가정
- 이때, 데이터 페이지를 압축할 용량이 얼마가 될지 알 수 없는데, 어떻게 KEY_BLOCK_SIZE 를 테이블을 생성할때 설정할 수 있는가?
- 우선, 아래는 InnoDB 스토리지 엔진이 압축을 적용하는 방법이다.
- 16KB의 데이터 페이지를 압축한다.1.2 압축된 결과가 8KB를 초과하면 원본 페이지를 스플릿(split) 해서 2개의 페이지에 8KB씩 저장한다.
- 1.1 압축된 결과가 8KB 이하이면 그대로 디스크에 저장한다. (압축 완료)
- 나뉜 페이지 각각에 대해 1번 단계를 반복실행한다.
- 위 그림은 테이블 압축 작동방식을 보여줌.
- 목표 크기를 (KEY_BLOCK_SIZE)로 8KB 를 가정함.
- 테이블 압축에서는 InnoDB 스토리지 엔진의 “InnoDB I/O 레이어” 에서는 아무 역할을 하지 않음.
- 테이블 압축 방식에서 가장 중요한 것은 원본 데이터 페이지의 압축 결과가 목표 크기(KEY_BLOCK_SIZE) 보다 작거나 같을 때까지 반복해서 페이지를 스플릿 하는 것임.
- 목표 크기가 잘못 설정되면 MySQL 서버의 처리 성능이 급격히 떨어질 수 있으니 주의해야함.
KEY_BLOCK_SIZE 결정
- 테이블 압축에서 가장 중요한 부분은 압축된 결과가 어느 정도 될지 예측해서 KEY_BLOCK_SIZE 를 결정해야 함.
- 테이블 압축을 적용하기 전에 먼저 KEY_BLOCK_SIZE 를 4KB 또는 8KB 로 테이블을 생성해서 샘플 데이터를 저장해보고 적절한지 판단하는것이 좋음.
- 이때, 샘플 데이터는 많으면 많을수록 더 정확한 테스트가 가능함.
- 최소한 테이블의 데이터 페이지가 10개 정도는 생성되도록 테스트 데이터를 INSERT 해보는 것이 좋음.
- 190p 에서 employees 테이블에 대한 KEY_BLOCK_SIZE 선택 예시를 자세히 설명하고 있음.
- 일반적으로 압축 실패율은 3~5% 미만으로 유지할 수 있게 KEY_BLOCK_SIZE 를 선택하는 것이 좋음.
- 압축 실패는 압축 결과가 4KB 를 초과해서 데이터 페이지를 스플릿하여 다시 압축을 실패하는 상황임.
- 압축 실패율이 높다고 해서 실제 디스크의 데이터 파일 크기가 줄어들지 않는다는 뜻은 아님.
- 일반적으로 압축 실패율은 3~5% 미만으로 유지할 수 있게 KEY_BLOCK_SIZE 를 선택하는 것이 좋음.
- 압축 실패율이 높다고 해서 압축을 사용하지 말아야 한다는 것은 아님.
- 한 번 정도 압축 시도가 실패해서 페이지 스플릿 후 재압축 하더라도 전체적으로 데이터 파일의 크기가 큰 폭으로 줄어든다면 큰 손해는 아님.
- 반대로, 압축 실패율이 높지 않은 경우라도 테이블의 데이터가 매우 빈번히 조회되고 변경된다면 압축은 고려하지 않는게 좋음.
- 테이블 압축은 zlib를 이용해 압축을 실행함.
- 예상외로 압축 알고리즘은 많은 CPU 자원을 소모한다는 사실을 기억해야 함.
압축된 페이지의 버퍼 풀 적재 및 사용
- InnoDB 스토리지 엔진은 압축된 테이블의 데이터 페이지를 버퍼 풀에 적재하면 압축된 상태와 압축이 해제된 상태 2개 버전을 관리함.
- 그래서 InnoDB 스토리지 엔진은 디스크에서 읽은 상태 그대로의 데이터 페이지 목록을 관리하는
LRU 리스트
와 압축된 페이지들의 압축 해제 버전인Unzip_LRU 리스트
를 별도로 관리한다.
- 그래서 InnoDB 스토리지 엔진은 디스크에서 읽은 상태 그대로의 데이터 페이지 목록을 관리하는
- MySQL 서버에는 압축된 테이블과 압축되지 않은 테이블이 공존하므로 결국 LRU 리스트는 다음의 압축된 페이지와 압축되지 않은 페이지를 모두 가질 수 있음.
- 압축이 적용되지 않은 테이블의 데이터 페이지
- 압축이 적용된 테이블의 압축된 페이지
- Unzip_LRU 리스트는 압축이 적용되지 않은 테이블의 데이터 페이지는 가지지 않음.
- 압축 적용된 테이블에서 읽은 데이터 페이지만 관리한다.
- 물론 이 리스트에는 압축을 해제한 상태의 데이터 페이지 목록이 관리된다.
- InnoDB 스토리지 엔진은 압축된 테이블에 대해서는 버퍼 풀의 공간을 이중으로 사용함으로써 메모리를 낭비하는 효과를 가짐.
- 또 다른 문제로, 압축된 페이지에서 데이터를 읽거나 변경하기 위해서는 압축을 해제해야 한다.
- 압축 & 압축 해제 작업은 CPU 를 상대적으로 많이 소모함.
- 위 두 단점을 보완하기 위해 Unzip_LRU 리스트를 별도로 관리하고 있다가 MySQL 서버로 유입되는 요청 패턴에 따라 적절히 다음과 같은 처리를 수행한다.
- InnoDB 버퍼 풀의 공간이 필요한 경우 LRU 리스트에서 원본 데이터 페이지(압축된 형태)는 유지하고 Unzip_LUR 리스트에서 압축 해제된 버전은 제거해서 버퍼 풀 공간을 확보한다.
- 압축된 데이터 페이지가 자주 사용되는 경우, Unzip_LUR 리스트에 압축 해제된 페이지를 계속 유지하면서 압축 및 압축 해제 작업을 최소화 한다.
- 압축된 데이터 페이지가 사용되지 않아 LRU 리스트에서 제거되는 경우, Unzip_LRU 리스트에서도 함께 제거된다.
- InnoDB 스토리지 엔진은 버퍼 풀에서 압축 해제된 버전의 데이터 페이지를 적절한 수준으로 유지하기 위해 다음과 같은 어댑티브 알고리즘을 사용한다.
- CPU 사용량이 높은 서버에서는 가능하면 압축과 압축 해제를 피하기 위해 Unzip_LRU 비율을 높여서 유지한다.
- Disk I/O 사용량이 높은 서버에서는 가능하면 Unzip_LRU 리스트 비율을 낮춰 InnoDB 버퍼 풀 공간을 더 확보하도록 작동한다.
테이블 압축 관련 설정
- 테이블 압축을 사용할 때 연관된 시스템 변수가 몇개 있음.
- 페이지 압축 실패율을 낮추기 위한 튜닝 포인트를 제공함.
innodb_cmp_per_index_enabled
: 테이블 압축이 사용된 테이블의 모든 인덱스별로 압축 성공 및 압축 실행 회수를 수집하도록 설정함.- 이 옵션이 비활성화 되면 테이블 단위의 압축 성공 및 실행 횟수만 수집된다.
- 테이블 단위로 수집된 정보는 information_schema.INNODB_CMP 테이블에 기록된다.
- 인덱스 단위로 수집된 정보는 information_schema.INNODB_CMP_PER_INDEX 테이블에 기록된다.
innodb_compression_level
: InnoDB 의 테이블 압축은 zlib 압축 알고리즘만 지원하는데, 이 시스템 변수를 이용해 압축률을 설정할 수 있음.- 0 ~ 9 까지 설정할 수 있음.
- 값이 작을 수록 압축 속도는 빨라지지만 저장 공간은 커질 수 있다.
- 값이 커질 수록 속도는 느려질 수 있지만 압축률은 높아짐.
- 기본값은 6으로, 압축 속도, 압축률 모두 중간정도로 선택한 값임.
- 여기서 압축 속도는 CPU 자원 소모량과 동일한 의미임.
- 즉, 압축 속도가 빨라진다는 것은 CPU 자원을 그만큼 적게 사용한다는 의미임.
- 0 ~ 9 까지 설정할 수 있음.
innodb_compression_failure_threshold_pct
와innodb_compression_pad_pct_max
: 테이블 단위로 압축 실패율이innodb_compression_failure_threshold_pct
시스템 설정값보다 커지면 압축을 실행하기 전 원본 데이터 페이지의 끝에 의도적으로 일정 크기의 빈 공간을 추가한다.- 즉, 추가된 빈 공간은 압축률을 높여 압축 결과가 KEY_BLOCK_SIZE 보다 작아지게 만드는 효과를 낸다.
- 여기서 추가된 빈 공간을 패딩(Padding) 이라고 한다.
- 이 패딩 공간은 압축 실패율이 높아질수록 계속 증가된 크기를 가짐.
- 추가할 수있는 패딩 공간의 최대 크기는
innodb_compression_pad_pct_max
시스템 설정값 이상을 넘을 수 없음.- 이 값은 % 값을 설정하는데, 전체 데이터 페이지 크기 대비 패딩 공간의 비율을 의미함.
innodb_log_compressed_pages
: MySQL 서버가 비정상적으로 종료됐다가 다시 시작되는 경우 압축 알고리즘(zlib)버전의 차이가 있더라도 복구 과정이 실패하지 않도록 InnoDb 스토리지 엔진은 압축된 데이터 페이지를 그대로 리두 로그에 기록한다.- 압축 알고리즘을 업그레이드할 때 도움이 됨.
- 하지만 데이터 페이지를 통째로 리두 로그에 저장하는 것은 리두 로그의 증가량에 상당한 영향을 미침.
- 압축 적용 후, 리두 로그 용량이 매우 빠르게 증가하거나 버퍼 풀로부터 더티페이지가 한꺼번에 많이 기록된다면,
innodb_log_compressed_pages
시스템 변수를 OFF 하고, 모니터링 해보는게 좋다.- 해당 변수는 기본값이 ON 임. 가능한 기본값을 유지하자.
'Book > Real Mysql 8.0' 카테고리의 다른 글
책너두 (Real MySQL 8.0 1권) 19일차 (~215p) (0) | 2023.01.24 |
---|---|
책너두 (Real MySQL 8.0 1권) 18일차 (~203p) (0) | 2023.01.23 |
책너두 (Real MySQL 8.0 1권) 16일차 (~184p) (0) | 2023.01.21 |
책너두 (Real MySQL 8.0 1권) 15일차 (~175p) (0) | 2023.01.20 |
책너두 (Real MySQL 8.0 1권) 14일차 (~169p) (1) | 2023.01.19 |