새소식

독서/RealMySQL 8.0

6. 데이터 압축

  • -

 Mysql 서버에서 디스크에 저장된 데이터 파일의 크기는 일반적으로 쿼리의 처리 성능과도 직결되지만 백업 및 복구 시간과도 밀접하게 연관된다. 디스크의 데이터 파일은 클수록 쿼리를 처리하기 위해서 더 많은 데이터 페이지를 InnoDB 버퍼 풀로 읽어야 할 수도 있고, 새로운 페이지가 버퍼 풀로 적재되기 때문에 그만큼 더티 페이지가 더 자주 디스크로 기록돼야 한다. 그리고 데이터 파일이 크면 백업 시간이 오래걸리며, 복구 하는데 시간이 오래 걸린다. 이런 문제를 해결하기 위해 데이터 압축 기능을 제공한다. 크게 테이블 압축, 페이지 압축 2가지로 구분할 수 있다.

 

1. 페이지 압축

: "Transparent Page Compression" 이라고도 불리며, Mysql 서버가 디스크에 저장하는 시점에 데이터 페이지가 압축되어 저장되고, 반대로 Mysql 서버가 디스크에서 데이터 페이지를 읽어올 때 압축이 해제되기 때문이다. 즉 버퍼 풀에 데이터 페이지가 한 번 적재되면 InnoDB 스토리지 엔진은 압축이 해제된 상태로만 데이터 페이지를 관리한다. 그래서 Mysql 서버의 내부 코드에서 압축 여부와 상관없이 "투명(Tranparent)"하게 작동한다.

 

 한가지 문제점은 16KB 데이터 페이지 압축 결과가 용량의 예측이 불가한데, 적어도 하나의 테이블은 동일한 크기의 페이지로 통일돼야 한다. 그래서 페이지 압축 기능은 os별로 특정 버전의 파일 시스템에서만 지원되는 펀치 홀(Punch hole) 기능을 제공한다. 만약 운영체제의 블록 사이즈가 512byte 경우, 페이지 압축이 작동하는 방식을 간단히 살펴보자. Mysql 서버는 특정 테이블에 대해 16KB 크기의 페이지를 유지하면서도 압축된 다양한 크기의 데이터 페이지를 디스크에 저장하고 압축된 만큼의 공간을 절약할 수 있다.

 

페이지 압축 작동 방식

1. 16KB 페이지를 압축 (압축 결과를 7KB로 가정)

2. Mysql 서버는 디스크에 압축된 결과 7KB를 기록 ( Mysql 서버는 압축 데이터 7KB에 9KB의 빈 데이터를 기록

3. 디스크에 데이터를 기록한 후, 7KB 이후의 공간 9KB에 대해 펀치 홀 생성

4. 파일 시스템은 7KB만 남기고, 나머지 디스크의 9KB 공간은 다시 운영체제로 반납

 

 펀치홀은 OS 뿐만 아니라 하드웨어 자체에서나 파일 시스템 관련 명령어(유틸리티)에서도 지원을 해야한다. 예를 들어 MySQL 서버의 데이터 파일을 백업했다 복구하는 과정에서 많은 파일관련 유틸리티를 사용하는데 이것이 펀치 홀을 지원하지 않으면 실제 데이터 파일의 크기는 원본 크기가 될 수 있다. 이런 이유로 페이지 압축은 많이 사용되지 않는다.

 

 

2. 테이블 압축

: 테이블 압축은 os, 하드웨어 제약 없이 사용할 수 있기에 활용도가 더 높다. 테이블 압축은 디스크의 데이터 파일 크기를 줄일 수 있기 때문에 그만큼 이득이 있지만 단점도 있다.

 

1. 버퍼 풀 공간 활용률이 낮음.

2. 쿼리 처리 성능이 낮음

3. 빈번한 데이터 변경 시 압축률이 떨어짐

 

 위를 이해하려면 내부적으로 어떻게 압축이 실행되어 디스크에 저장되고, 압축된 데이터 페이지들이 버퍼 풀에 어떻게 적재되어 사용되는지를 이해해야 한다.

 

 

6.2.1 압축 테이블 생성

: 테이블 압축을 사용하기 위한 전제 조건으로 압축을 사용하려는 테이블이 별도의 테이블 스페이스를 사용해야 한다. 이를 위해 innodb_file_per_table 시스템 변수가 ON으로 설정된 상태에서 테이블이 생성돼야한다. 테이블 압축을 사용하는 테이블은 ROW_FORMAT=COMPRESSED 옵션을 명시해야 한다. KEY_BLOCK_SIZE 옵션을 이용해 압축된 페이지의 타깃 크기를 명시하는데, 2n으로만 설정할 수 있다.

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> mysql> CREATE TABLE compressed_table (
		c1 INT PRIMARY KEY,
        )
        KEY_BLOCK_SIZE=8;

 

 InnoDB 스토리지 엔진의 데이터 페이지(블록)의 크기가 16KB, 그리고 KEY_BLOCK_SIZE=8인 경우에 압축을 적용하는 방법은 다음과 같다.

 

1. 16KB의 데이터 페이지 압축
2. 압축된 결과가 8KB 이하이면 그대로 디스크에 저장 (압축 완료)
3. 압축된 결과가 8KB 보다 크면 원본 페이지를 분리(split)해서 2개의 페이지에 8KB씩 저장 (압축 실패)

4. 3에서 나뉜 페이지에 대해 각각 1,2,3 과정 반복 시행

 

 재귀함수 형태로 압축을 적용하는 것과 KEY_BLOCK_SIZE 값이 압축 성공률을 결정하는 가장 큰 요인이라는 것을 알 수 있다.

따라서, KEY_BLOCK_SIZE 값을 잘 설정해야 하는데 어떻게 최적값을 찾을 수 있을까?

 

 

6.2.2 KEY_BLOCK_SIZE 결정

: 압축 실패율은 3% ~ 5% 미만 수준으로 유지하는 것이 좋다. 압축 실패율이 높지만 압축으로 인해 데이터 파일의 크기가 큰 폭으로 줄어드는 경우 압축을 고려해볼 필요가 있다. 압축 알고리즘은 생각보다 많은 CPU 자원을 소모하므로, 테이블이 자주 조회되고 변경된다면 고려하지 않는 편이 좋다.

 

 

6.2.3 압축된 페이지의 버퍼 풀 적재 및 사용

: InnoDB 스토리지 엔진은 압축된 테이블의 데이터 페이지를 버퍼 풀에 적재하면 압축된 상태와 압축이 해제된 상태 2개의 버전을 관리한다. 결국 InnoDB 스토리지 엔진은 압축된 테이블에 대해 버퍼 풀의 공간을 이중으로 사용하기에 메모리를 낭비하게 된다. 또한, 압축된 페이지의 데이터를 읽거나 변경하기 위해서는 압축을 해제해야 하는데 이는 많은 CPU 자원을 소모한다.

 

이러한 단점을 보완하기 위해 Unzip_LRU 리스트를 별도로 관리하고 있다가 Mysql 서버로 유입되는 요청 패턴에 따라서 적절히 아래와 같은 처리를 수행한다.

 

1. InnoDB 버퍼 풀의 공간이 필요한 경우에는 LRU 리스트에서 원본 데이터 페이지는 유지하고, Unzip_LRU 리스트에서 압축 해제된 버전은 제거해서 버퍼 풀의 공간을 확보한다.

2. 압축된 데이터 페이지가 자주 사용되는 경우에는 Unzip_LRU 리스트에 압축 해제된 페이지를 계속 유지하면서 압축 및 해제 작업을 최소화한다.

3. 압축된 데이터 페이지가 사용되지 않아서 LRU 리스트에서 제거되는 경우는 Unzip_LRU 리스트에서도 함께 제거된다.

 

InnoDB 스토리지 엔진은 위를 수행하기 위해 아래와 같은 알고리즘을 사용한다.

1. CPU 사용량이 높은 서버에서는 가능하면 압축과 압축 해제를 피하기 위해 Unzip_LRU 비율을 높여서 유지하고

2. Disk IO 사용량이 높은 서버는 가능하면 Unzip_LRU 리스트 비율을 낮춰서 InnoDB 버퍼 풀 공간을 확보하도록 작동한다.

'독서 > RealMySQL 8.0' 카테고리의 다른 글

8. 인덱스 (상)  (1) 2024.01.21
7. 데이터 암호화  (0) 2024.01.14
5. 트랜잭션  (1) 2024.01.07
4.3 아키텍처 (하)  (2) 2024.01.07
4.2 아키텍처 (중)  (1) 2024.01.04
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.