6장 데이터 압축
- 디스크의 데이터 크기 크면 클수록!
- 버퍼 풀로 더 많은 데이터를 읽어야 한다.
- 더티 페이지가 더 자주 디스크로 기록되어야 한다.
- 백업 및 복구하는데 시간이 더 소요된다.
- 비용문제가 발생한다.
- 그래서 DBMS에서는 데이터 압축 기능을 제공한다.
- 기본적으로 압축이 이루어지면 성능은 저하된다. (압축과 해제에 대한 비용발생)
- 데이터 압축은 크게 테이블 압축과 페이지 압축으로 나뉘어진다.
6.1 페이지압축
- MySQL 서버가 디스크에 저장하는 시점에 데이터 페이지가 압축되어 저장되고, 읽어들이는 시점에 데이터 페이지가 압축 해제되어 읽는다.
- 즉, InnoDB 스토리지 엔진은 압축해제 상태에서 데이터 페이지를 관리한다.
- 펀치홀
- 데이터 페이지를 압축하고나서 남는 공간을 의미한다.
- 예를들어 16KB 페이지를 압축하여 7KB가 되었고 이를 디스크에 저장하면 7KB만 기록하고 9KB는 빈 데이터를 기록한다.
- 이후에 9KB에 대해 펀치홀을 생성하고 이를 운영체제로 반납한다.
- 그러나 이 펀치홀 기능은 운영체제가 지원해야 사용이 가능하고 뿐만아니라 하드웨어에서도 해당 기능을 지원해줘야한다.
- 또한 파일 시스템 관련 명령어가 펀치홀을 지원하지 못한다. 복사 복제하는 과정에서도 원본크기의 복사가 이루어질 수 있다.
- 이런 이유로 잘 사용되지 않는다.
6.2 테이블 압축
- 테이블 압축은 페이지 압축과 달리 운영체제나 하드웨어의 제약 없이 사용가능하다.
- 그래도 몇 가지 단점이 존재한다.
- 버퍼 풀 공간 활용률이 낮음
- 쿼리 처리 성능이 낮음
- 빈번한 데이터 변경 시 압축률이 떨어짐
6.2.1 압축 테이블 생성
- 압축 테이블을 생성하려면 먼저 별도의 테이블 스페이스를 사용해야 한다. (innodb_file_per_table 시스템 변수 ON 상태)
- 테이블을 생성할 때 ROW_FORMAT=COMPRESSED 옵션 설정, KEY_BLOCK_SIZE 옵션을 이용해서 압축된 타깃의 사이즈를 명시한다.
- KEY_BLOCK_SIZE는 2n(n>=2)으로만 설정할 수 있다.
- 예를들어 현재 페이지가 16KB 라면 4KB 또는 8KB로만 설정할 수 있다.
CREATE TABLE COMPRESSED_TABLE(
C1 INT PRIMARY KEY,
)
ROW_FORMAT=COMPRESSED
KEY_BLOCK_SIZE=8;
- InnoDB 스토리지 엔진의 압축 절차 예시 (페이지 크기 = 16KB, KEY_BLOCK_SIZE = 8)
- 16KB의 데이터 페이지를 압축
- 압축된 결과가 8KB이하이면 그대로 디스크에 저장(압축 완료)
- 압축된 결과가 8KB를 초과하면 원본 페이지를 스플릿해서 2개의 페이지에 8KB 씩 저장
- 나뉜 페이지 각각에 대해 1번 단계를 반복 실행
- 중요한 것은 페이지의 압축 결과가 목표 크기(KEY_BLOCK_SIZE)보다 작거나 같을 때까지 반복해서 페이지를 스플릿하는 것이다.
6.2.2 KEY_BLOCK_SIZE 결정
- 테이블 압축에서 가장 중요한 부분이 압축된 결과가 어느 정도가 될지 예측해서 KEY_BLOCK_SIZE를 결정하는 것이다.
- 샘플 데이터를 저장해보고 적절한지 판단하는 것이 좋다.
SELECT table_name, index_name, compress_ops, compress_ops_ok,
(compress_ops-compress_ops_ok)/compress_ops * 100 as compress_failure_pct
FROM information_schema.INNODB_CMP_PER_INDEX;
- 압축 실패율이 높다고 해서 압축을 사용하지 말아야 하는것은 아니다.
- 반대로 압축 실패욜이 낮다고 해서 압축을 해야한다는 것도 아니다.
- 압축 알고리즘은 많은 CPU자원을 소모한다.
6.2.3 압축된 페이지의 버퍼 풀 적재 및 사용
- 압축된 테이블의 데이터 페이지를 버퍼 풀에 적재하면 압축된 상태와 압축이 해제된 상태 2개 버전을 관리한다.
- 그래서 InnoDB 스토리지 엔진은 압축된 그대로의 데이터 페이지를 관리하는 LRU, 압축이 해제된 페이지를 관리하는 Unzip_LRU 리스트를 별도로 관리한다.
- 압축된 테이블에 대해서는 버퍼 풀의 공간을 이중으로 사용함으로써 메모리를 낭비하는 효과가 있다.
- 이를 관리하기위해 Adaptive 알고리즘을 사용한다.
6.2.4 테이블 압축 관련 설정
- 테이블 압축에 연관된 여러 시스템 변수가 있다. 이는 압축 실패율을 낮추기 위한 튜닝 포인트를 제공한다.
- innodb_cmp_per_index_enabled
- innodb_compression_level
- innodb_compression_failure_threshold_pct, innodb_compression_pad_pct_max
- innodb_log_compressed_pages
7장 데이터 암호화
- 데이터 암호화 여부는 보안 감사에서 필수적으로 언급되는 부분이다.
- 핀테크 서비스처럼 중요한 정보를 저장하는 서비스는 응용프로그램에서 암호화한 데이터를 데이터베이스 서버에서 암호화하는 이중 암호화 방법을 선택하기도 한다.
- 이번 장에서는 MySQL 서버에서 암호화하는 방식을 알아본다.
7.1 MySQL 서버의 데이터 암호화
- MySQL 서버에서는 데이터베이스 서버와 디스크 사이의 데이터를 읽고 쓰는 지점에서 암호화와 복호화를 수행한다. (InnoDB 스토리지 엔진의 I/O 레이어)
- 따라서 MySQL 서버의 사용자는 쿼리를 사용하는 데에 아무런 차이가 없다.
- 이러한 암호화 방식을 TDE(Transparent Data Encryption) 또는 Data at Rest Encryption 이라고 한다. (at Rest : 디스크에 저장된 상태)
7.1.1 2단계 키 관리
- TDE에서 암호화 키는 키링(KeyRing) 플러그인에 의해 관리된다.
- 여러 키링 관리 플러그인이 존재하지만 이는 다 마스터 키를 관리하는 방법만 다르고 작동하는 방식은 동일하다.
- MySQL 서버의 키링 플러그인은 2단계 (2-Tier) 키 관리 방식을 사용한다.
MySQL 서버의 테이블 암호화
- MySQL 서버에서는 두 가지 키로 암호화를 한다.
- 마스터 키
- 테이블 스페이스 키
- 절차
- 디스크의 keyring_file에서 마스터 키를 가져온다.
- 암호화된 테이블이 생성되면 테이블 스페이스 키를 발급한다. (테이블 스페이스 키는 절대 변경되지 않는다.)
- 마스터 키를 이용해서 테이블 스페이스 키를 암호화해서 각 테이블의 데이터파일 헤더에 저장한다.
- 테이블의 데이터가 저장될 때 테이블 스페이스 키를 이용해서 암호화하여 저장한다.
- 암호화 알고리즘
- MySQL TDE 에서 지원되는 암호화 알고리즘은 AES 256이다.
- 마스터키는 변경할 수 있다.
- ALTER INSTANCE ROTATE INNODB MASTER KEY;
7.1.2 암호화와 성능
- MySQL 서버의 암호화 방식은 TDE 방식이다. 따라서 한 번 메모리에 적재하면 암호화되지 않은 테이블과 동일한 성능을 보인다.
- 하지만 InnoDB 버퍼 풀에 존재하지 않는 데이터 페이지를 읽어야 한다면 복호화하는 시간이 더 발생한다.
- 또한 암호화된 테이블이 변경된다면 디스크로 동기화할 때 암호화하는 시간이 더 발생한다.
- 이는 백그라운드 스레드가 수행하기 때문에 쿼리가 지연되지는 않는다.
- AES 암호화 알고리즘은 평문의 데이터가 충분히 크다면 파일의 크기는 암호화 전과 후가 크게 다르지 않다.
- 암호화와 압축이 동시에 적용되면 MySQL 서버는 압축을 먼저 실행하고 암호화를 한다.
- 암호화된 결과문은 아주 랜덤한 바이트 배열을 가지게 되어 압축률을 상당히 떨어뜨린다.
7.1.3 암호화와 복제
- MySQL 서버의 복제에서 레플리카 서버는 TDE를 이용한 암호화 사용 시 마스터 키와 테이블스페이스 키는 기본적으로 새로 할당된다.
- 소스 서버와 레플리카 서버는 서로 각자의 마스터 키와 테이블스페이스 키를 관리하기 때문에 복제 멤버들의 데이터 파일은 암호화 되기 전의 값이 동일하더라도 실제 암호화된 데이터가 저장된 데이터 파일의 내용은 완전히 달라진다.
- 마스터키 로테이션을 실행하면 소스 서버와 레플리카 서버가 서로 다른 마스터 키를 새로 발급받는다.
- 백업을 할 경우 TDE의 키링 파일을 백업하지 않으면 데이터를 복구 할 수 없게 된다.
7.2 keyring_file 플러그인 설치
- keyring_file 플러그인은 커뮤니티 에디션에서 사용 가능한 플러그인이다.
- 테이블스페이스 키를 암호화하기 위한 마스터 키를 디스크의 파일로 관리한다.
- 이때 마스터 키는 평문으로 디스크에 저장된다.
- 마스터 키 초기화
- ALTER INSTANCE ROTATE INNODB MASTER KEY;
7.3 테이블 암호화
- 키링 파일 플러그인은 마스터 키 생성까지만 담당하기 때문에 어떤 플러그인을 쓰더라도 테이블 암호화하는 방식은 동일하다.
7.3.1 테이블 생성
- 테이블 생성 구문 마지막에 ENCRYPTION='Y' 옵션만 추가로 넣으면 된다.
- 모든 테이블에 대해 암호화를 적용하고자 한다면 default_table_encryption 시스템 변수를 ON으로 설정하면 된다.
7.3.2 응용 프로그램 암호화와의 비교
- 응용 프로그램으로 암호화된 컬럼은 인덱스를 생성하더라도 그 기능을 활용할 수 없다.
- MySQL 서버 암호화와 응용 프로그램 암호화 기능 중 선택할 수 있는 상황이면 MySQL 서버 암호화를 선택 하는게 좋다.
- 목적과 용도가 둘이 다르긴 하다.
- 서버 암호화가 되어있어도 사용자는 모든 데이터를 조회할 수 있다.
- 응용 프로그램 암호화가 되어있으면 사용자는 암호화된 데이터를 조회하게 된다.
7.3.3 테이블스페이스 이동
- 테이블을 다른 서버로 복사해야 하는 경우 또는 특정 테이블의 데이터 파일만 백업했다가 복구하는 경우라면 테이블스페이스 이동(Export & Import)기능이 레코드를 덤프했다가 복구하는 방식보다 훨씬 빠르고 효율적이다.
- FLUSH TABLES source_table FOR EXPORT
- 암호화된 테이블의 경우 테이블스페이스 이동 기능을 사용할 때는 반드시 데이터 파일과 임시 마스터 키가 저장된 \*.cfp 파일을 함께 복사해야 한다.
7.4 언두 로그 및 리두 로그 암호화
- 테이블 암호화를 적용해도 리두 로그나 언두 로그, 그리고 복제를 위한 바이너리 로그에는 평문으로 저장된다.
- MySQL 8.0.16 버전부터는 innodb_undo_log_encrypt, innodb_redo_log_encrypt 시스템 변수들로 InnoDB 스토리지 엔진의 리두 로그와 언두 로그를 암호화된 상태로 저장할 수 있게 개선됐다.
- 별도의 테이블 스페이스 키로 이들 데이터가 암호화된다.
7.5 바이너리 로그 암호화
7.5.1 바이너리 로그 암호화 키 관리
- 바이너리 로그와 릴레이 로그 파일의 데이터는 파일 키(FIle Key)로 암호화해서 디스크로 저장하고, 파일 키는 "바이너리 로그 암호화 키"로 암호화해서 각 바이너리 로그와 릴레이 로그 파일의 헤더에 저장된다.
- 파일 키는 바이너리 로그와 릴레이 로그 파일 단위로 자동 생성되어 해당 로그 파일의 데이터 암호화에만 사용된다.
7.5.2 바이너리 로그 암호화 키 변경
명령어
- ALTER INSTANCE ROTATE BINLOG MASTER KEY;
변경 과정
- 증가된 시퀀스 번호화 함께 새로운 바이너리 로그 암호화 키 발급 후 키링 파일에 저장
- 바이너리 로그 파일과 릴레이 로그 파일 스위치(새로운 로그 파일로 로테이션)
- 새로 생성되는 바이너리 로그와 릴레이 로그 파일의 암호화를 위해 파일 키를 생성하고, 파일 키는 바이너리 로그 파일 키(마스터 키)로 암호화해서 각 로그 파일에 저장
- 기존 바이너리 로그와 릴레이 로그 파일의 파일 키를 읽어서 새로운 바이너리 로그 파일 키로 암호화해서 다시 저장
- 모든 바이너리 로그와 릴레이 로그 파일이 새로운 바이너리 로그 암호화 키로 다시 암호화됐다면 기존 바이너리 로그 암호화 키를 키링 파일에서 제거
7.5.3 mysqlbinlog 도구 활용
- 바이너리 로그 암호화 키는 MySQL 서버만 가지고 있어서 바이너리 로그 파일을 외부에서 복호화가 불가능하다.
- 그래서 암호화된 바이너리 로그 파일의 내용을 볼 수 있는 방법은 MySQL 서버를 통해 가져오는 방법이 유일하다.
- mysqlbinlog 명령을 실행할 때 "--read-from-remote-server" 파라미터와 함께 접속 정보를 입력한다.