MySQL 서버에서 디스크에 저장된 데이터 파일의 크기는 일반적으로 쿼리의 처리 성능과도 직결되지만 백업 및 복구 시간과도 밀접하게 연결된다. 디스크의 데이터 파일이 크면 클수록 쿼리를 처리하기 위해서 더 많은 데이터 페이지를 InnoDB 버퍼 풀로 읽어야 할 수도 있고, 새로운 페이지가 버퍼 풀로 적재되기 때문에 그만큼 더티 페이지가 더 자주 디스크로 기록돼야 한다. 그리고 데이터 파일이 크면 클수록 백업 시간이 오래 걸리며, 복구하는 데도 그만큼의 시간이 걸린다. 물론 그만큼의 저장 공간이 필요하기 때문에 비용 문제도 있을 수 있다.
많은 DBMS가 이런 문제점을 해결하기 위해 데이터 압축 기능을 제공한다.
MySQL 서버에서 사용 가능한 압축 방식은 크게 테이블 압축과 페이지 압축의 두 가지 종류로 구분할 수 있다. 차례로 살펴본다.
▶ 페이지 압축
- MySQL 서버가 디스크에 저장하는 시점에 데이터 페이지가 압축되어 저장되고, 반대로 MySQL 서버가 디스크에서 데이터 페이지를 읽어올 때 압축이 해제되기 때문이다.
- 즉 버퍼 풀에 데이터 페이지가 한 번 적재되면 InnoDB 스토리지 엔진은 압축이 해제된 상태로만 데이터 페이지를 관리한다. 그래서 MySQL 서버의 내부 코드에서는 압축 여부와 관계없이 "투명(Tranparent)"하게 작동한다.
- 여기서 한 가지 문제점이 있는데, 16KB 데이터 페이지를 압축한 결과가 용량이 얼마나 될지 예측이 불가능한데 적어도 하나의 테이블은 동일한 크기의 페이지(블록)로 통일돼야 한다는 것이다.
- 그래서 페이지 압축 기능은 운영체제별로 특정 버전의 파일 시스템에서만 지원되는 펀치 홀(Punch hole)이라는 기능을 사용한다.
- MySQL 서버의 페이지 압축이 가진 문제는 펀치 홀 기능은 운영체제 뿐만 아니라 하드웨어 자체에서도 해당 기능을 지원해야 사용가능하다는 점이다.
- 이런 이유로 실제 페이지 압축은 많이 사용되지 않는다.
▶ 테이블 압축
- 테이블 압축은 운영체제나 하드웨어에 대한 제약 없이 사용할 수 있기 때문에 일반적으로 더 활용도가 높은 편이다.
- 테이블 압축은 우선 디스크의 데이터 피일 크기를 줄일 수 있기 때문에 그만큼의 이득은 있지만 몇 가지 단점도 존재한다.
- 버퍼 풀 공간 활용률이 낮음
- 쿼리 처리 성능이 낮음
- 빈번한 데이터 변경 시 압축률이 떨어짐
▶ 압축 테이블 생성
- 테이블 압축을 사용하기 위한 전제 조건으로 압축을 사용하려는 테이블이 별도의 테이블 스페이스를 사용해야 한다.
우선 InnoDB 스토리지 엔진이 압축을 적용하는 방법을 한 번 살펴보자.
- 16KB의 데이터 페이지를 압축
- 압축된 결과가 8KB 이하이면 그대로 디스크에 저장(압축 완료)
- 압축된 결과가 8KB를 초과하면 원본 페이지를 스플릿(split)해서 2개의 페이지에 8KB씩 저장
- 나뉜 페이지 각각에 대해 "1번" 단계를 반복 실행
→ 테이블 압축 방식에서 가장 중요한 것은 원본 데이터 페이지의 압축 결과가 목표크기보다 작거나 같을 때까지 반복해서 페이지를 스플릿하는 것이다. 그래서 목표 크기가 잘못 설정되면 MySQL 서버의 처리 성능이 급격히 떨어질 수 있으니 주의해야 한다.
- 압축 실패율을 보았을 때 실패율이 높다고 해서 압축을 사용하지 말아야 한다는 것을 의미하지는 않는다.
- 예를 들어, INSERT만 되는 로그 테이블의 경우에는 한 번 INSERT되면 이후 다시는 변경되지 않을 것이다.
- 그렇다면 한 번 정도는 압축 시도가 실패해서 페이지 스플릿 후 재압축한다고 하더라도 전체적으로 데이터 파일의 크기가 큰 폭으로 줄어든다면 큰 손해는 아닐 것이다.
물론 그 반대 경우도 존재한다.
- 압축 실패율이 그다지 높지 않은 경우라고 하더라도 테이블의 데이터가 매우 빈번하게 조회되고 변경된다면 압축은 고려하지 않는 것이 좋다.
▶ 압축된 페이지의 버퍼 풀 적재 및 사용
- InnoDB 스토리지 엔진은 압축된 테이블의 데이터 페이지를 버퍼 풀에 적재하면 압축된 상태와 압축이 해제된 상태 2개 버전을 관리한다.
- 그래서 InnoDB 스토리지 엔진은 디스크에서 읽은 상태 그대로의 데이터 페이지 목록을 관리하는 LRU 리스트와 압축된 페이지들의 압축 해제 버전인 Unzip_LRU 리스트를 별도로 관리한다.
MySQL 서버에는 압축된 테이블과 압축되지 않은 테이블이 공존하므로 결국 LRU 리스트는 다음과 같이 압축된 페이지와 압축되지 않은 페이지를 모두 가질 수 있다.
- 압축이 적용되지 않은 테이블의 데이터 페이지
- 압축이 적용된 테이블의 압축된 데이터 페이지
- 결국 InnoDB 스토리지 엔진은 압축된 테이블에 대해서는 버퍼 풀의 공간을 이중으로 사용함으로써 메모리를 낭비하는 효과를 가진다.
- 또 다른 문제점으로는 압축된 페이지에서 데이터를 읽거나 변경하기 위해서는 압축을 해제해야 한다는 것인데, 압축 및 해제 작업은 CPU를 상대적으로 많이 소모하는 작업이다.
- 이러한 두 가지 단점을 보완하기 위해 Unzip_LRU 리스트를 별도로 관리하고 있다가 MySQL 서버로 유입되는 요청 패턴에 따라서 적절히(Adaptive) 다음과 같은 처리를 수행한다.
- InnoDB 버퍼 풀의 공간이 필요한 경우에는 LRU 리스트에서 원본 데이터 페이지(압축된 형태)는 유지하고, Unzip_LRU 리스트에서 압축 해제된 버전은 제거해서 버퍼 풀의 공간을 확보한다.
- 압축된 데이터 페이지가 자주 사용되는 경우에는 Unzip_LRU 리스트에 압축 해제된 페이지를 계속 유지하면서 압축 및 압축 해제 작업을 최소화한다.
- 압축된 데이터 페이지가 사용되지 않아서 LRU 리스트에서 제거되는 경우에는 Unzip_LRU 리스트에서도 함께 제거된다.
→ InnoDB 스토리지 엔진은 버퍼 풀에서 압축 해제된 버전의 데이터 페이지를 적절한 수준으로 유지하기 위해 다음과 같은 어댑티브(적응적인) 알고리즘을 사용한다.
- CPU 사용량이 높은 서버에서는 가능하면 압축과 압축 해제를 피하기 위해 Unzip_LRU의 비율을 높여서 유지하고
- Disk IO 사용량이 높은 서버에서는 가능하면 Unzip_LRU 리스트의 비율을 낮춰서 InnoDB 버퍼 풀의 공간을 더 확보하도록 작동한다.
'CS > MySQL' 카테고리의 다른 글
MySQL B-Tree 인덱스 [2/2] (0) | 2023.07.06 |
---|---|
MySQL 인덱스(index)와 B-Tree 인덱스 [1/2] (0) | 2023.07.05 |
MySQL InnoDB 스토리지 엔진 잠금과 MySQL 격리 수준 (0) | 2023.07.02 |
MySQL 트랜잭션이란? MySQL 잠금(Lock) (0) | 2023.07.01 |
MySQL InnoDB 스토리지 엔진 아키텍처 / MVCC / 자동 데드락 감지 / 자동화 장애 복구 (0) | 2023.06.25 |