본문 바로가기

DB

Real MySQL 6장 데이터압축, 7장 데이터 암호화

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)
    1. 16KB의 데이터 페이지를 압축
      1. 압축된 결과가 8KB이하이면 그대로 디스크에 저장(압축 완료)
      2. 압축된 결과가 8KB를 초과하면 원본 페이지를 스플릿해서 2개의 페이지에 8KB 씩 저장
    2. 나뉜 페이지 각각에 대해 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 서버에서는 두 가지 키로 암호화를 한다.
    1. 마스터 키
    2. 테이블 스페이스 키
  • 절차
    1. 디스크의 keyring_file에서 마스터 키를 가져온다.
    2. 암호화된 테이블이 생성되면 테이블 스페이스 키를 발급한다. (테이블 스페이스 키는 절대 변경되지 않는다.)
    3. 마스터 키를 이용해서 테이블 스페이스 키를 암호화해서 각 테이블의 데이터파일 헤더에 저장한다.
    4. 테이블의 데이터가 저장될 때 테이블 스페이스 키를 이용해서 암호화하여 저장한다.
  • 암호화 알고리즘
    • 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;

변경 과정

  1. 증가된 시퀀스 번호화 함께 새로운 바이너리 로그 암호화 키 발급 후 키링 파일에 저장
  2. 바이너리 로그 파일과 릴레이 로그 파일 스위치(새로운 로그 파일로 로테이션)
  3. 새로 생성되는 바이너리 로그와 릴레이 로그 파일의 암호화를 위해 파일 키를 생성하고, 파일 키는 바이너리 로그 파일 키(마스터 키)로 암호화해서 각 로그 파일에 저장
  4. 기존 바이너리 로그와 릴레이 로그 파일의 파일 키를 읽어서 새로운 바이너리 로그 파일 키로 암호화해서 다시 저장
  5. 모든 바이너리 로그와 릴레이 로그 파일이 새로운 바이너리 로그 암호화 키로 다시 암호화됐다면 기존 바이너리 로그 암호화 키를 키링 파일에서 제거

7.5.3 mysqlbinlog 도구 활용

  • 바이너리 로그 암호화 키는 MySQL 서버만 가지고 있어서 바이너리 로그 파일을 외부에서 복호화가 불가능하다.
  • 그래서 암호화된 바이너리 로그 파일의 내용을 볼 수 있는 방법은 MySQL 서버를 통해 가져오는 방법이 유일하다.
    • mysqlbinlog 명령을 실행할 때 "--read-from-remote-server" 파라미터와 함께 접속 정보를 입력한다.

'DB' 카테고리의 다른 글

JDBC란? (SQL Mapper, ORM)  (0) 2022.06.03
Real MySQL 8장 인덱스 #1 (~8.5)  (0) 2022.05.27
Real MySQL 5장 트랜잭션과 잠금  (0) 2022.05.25
Real MySQL 4장 아키텍처  (0) 2022.05.24
Real MySQL 1장 ~ 3장  (0) 2022.05.23