책너두 (Real MySQL 8.0 1권) 17일차 (~194p)

현재 책너두 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바이트인 경우, 페이지 압축이 작동하는 방식은 다음과 같다.
    1. 16KB 페이지를 압축함. (압축 결과가 7KB 로 가정)
    2. MySQL 서버는 디스크에 압축된 결과인 7KB 를 기록함. (이때, MySQL 서버는 압축 데이터 7KB에 9KB의 빈 데이터를 기록한다.)
    3. 디스크에 데이터를 기록한 후, 7KB 이후의 공간 9KB에 대해 펀치 홀(Punch-hole)을 생성한다.
    4. 파일 시스템은 7KB만 남기고 나머지 디스크의 9KB 공간은 다시 운영체제로 반납한다.
  • 위 그림의 오른쪽 상태에서 펀치 홀이 9KB 만큼 생성되면서 실제 디스크의 공간은 7KB만 차지한다.
    • 하지만 운영체제에서는 16KB를 읽으면 압축된 데이터 7KB와 펀치 홀 공간인 9KB를 합쳐서 16KB를 읽음.
  • MySQL 서버의 페이지 압축이 가진 문제는 펀치 홀 기능이 운영체제뿐만 아니라 하드웨어 자체에서도 해당 기능을 지원해야 사용가능하다는 점임.
  • 또 다른 문제점으로 아직 파일 시스템 관련 명령어(유틸리티)가 펀치 홀을 지원하지 못한다는 것이다.
    • MySQL 서버의 데이터 파일은 해당 서버에만 머무는 것이 아님.
      • 데이터 파일을 백업했다가 복구하는 과정에서 데이터 파일 복사 과정이 실행되고 그 외에도 많은 파일 관련 유틸리티들을 사용한다.
        • ex) 펀치 홀이 적용되어 실제 데이터 파일의 크기가 1GB 라고 하더라도 “cp” 와 같은 파일 복사 명령, 또는 XtraBackup 같은 툴이 파일을 복사하면 펀치 홀이 다시 채워져서 데이터 파일의 크기는 원본 크기인 10GB가 될 수도 있음.
  • 위와 같은 이유로 실제 페이지 압축은 많이 사용되지 않는 상태임.
  • 페이지 압축을 이용하기 위해서는 테이블을 생성하거나 변경할 때 다음과 같이 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 스토리지 엔진이 압축을 적용하는 방법이다.
    1. 16KB의 데이터 페이지를 압축한다.1.2 압축된 결과가 8KB를 초과하면 원본 페이지를 스플릿(split) 해서 2개의 페이지에 8KB씩 저장한다.
    2. 1.1 압축된 결과가 8KB 이하이면 그대로 디스크에 저장한다. (압축 완료)
    3. 나뉜 페이지 각각에 대해 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 를 초과해서 데이터 페이지를 스플릿하여 다시 압축을 실패하는 상황임.
    • 압축 실패율이 높다고 해서 실제 디스크의 데이터 파일 크기가 줄어들지 않는다는 뜻은 아님.
  • 압축 실패율이 높다고 해서 압축을 사용하지 말아야 한다는 것은 아님.
    • 한 번 정도 압축 시도가 실패해서 페이지 스플릿 후 재압축 하더라도 전체적으로 데이터 파일의 크기가 큰 폭으로 줄어든다면 큰 손해는 아님.
    • 반대로, 압축 실패율이 높지 않은 경우라도 테이블의 데이터가 매우 빈번히 조회되고 변경된다면 압축은 고려하지 않는게 좋음.
  • 테이블 압축은 zlib를 이용해 압축을 실행함.
    • 예상외로 압축 알고리즘은 많은 CPU 자원을 소모한다는 사실을 기억해야 함.

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

  • InnoDB 스토리지 엔진은 압축된 테이블의 데이터 페이지를 버퍼 풀에 적재하면 압축된 상태압축이 해제된 상태 2개 버전을 관리함.
    • 그래서 InnoDB 스토리지 엔진은 디스크에서 읽은 상태 그대로의 데이터 페이지 목록을 관리하는 LRU 리스트와 압축된 페이지들의 압축 해제 버전인 Unzip_LRU 리스트를 별도로 관리한다.
  • 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 자원을 그만큼 적게 사용한다는 의미임.
    • innodb_compression_failure_threshold_pctinnodb_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 임. 가능한 기본값을 유지하자.

댓글

Designed by JB FACTORY