Database/Mysql

[Real MySQL] 4-2. 아키텍쳐: InnoDB 스토리지 엔진 아키텍쳐

noahkim_ 2023. 11. 24. 00:57

"Real MySQL" 책을 정리한 포스팅 입니다.

 

아키텍쳐

기능
  • 잠금 (레코드 기반)

 

장점
  • 성능
  • 높은 동시성 처리
  • 안정적

 

클러스터링 (by primary key)

  • 프라이머리 키를 기준으로 데이터가 정렬되어 저장됨
  • 프라이머리 키는 다른 보조 인덱스에 비해 가중치가 높게 설정됨

 

외래 키 지원

  • 슈퍼타입-서브타입 모두 해당 컬럼에 인덱스 생성 필요
    • 잠금이 여러 테이블로 전파됨 (데드락 발생 가능성 O)
  • foreign_key_checks(참조 무결성 제약원칙 체크 활성화)
    • OFF: 외래 키 관계의 부모 테이블에 대한 작업 무시 (cascade)

 

MVCC (Multi Version Concurrency Control)

  • 레코드 레벨의 동시성 제어 기법

 

Non-Locking Consistent Reads

  • 하나의 레코드에 대해 두 개의 버전으로 관리
  • 가장 최신의 일관된 상태 제공
    • (트랜잭션의 시작 시점 기준) 직전 버전의 데이터 확인
  • 여러 트랜잭션이 동시에 읽을 때, 잠금 필요 X
  • Undo Log 이용하여 구현
    • 데이터의 이전 버전들을 보관하는데 사용

 

UPDATE
  • Inno Buffer Pool: 갱신된 값을 기록
  • Undo Log: 현재 값을 기록

 

Commit
  • Disk: Inno Buffer Pool 값을 디스크로 플러시
  • Undo Log: (해당 커밋에 관련된 트랜잭션이 없다면) 값 초기화

 

Rollback
  • Inno Buffer Pool : Undo Log값을 기록
  • Undo Log : 현재 값을 기록

 

자동 데드락 감지

잠금 대기 목록
  • 그래프 형태
  • 교착 상태에 빠진 트랜잭션 관리용

 

데드락 감지 (주기적)
  • 데드락 감지 스레드 사용
  • 잠금 대기 목록 사용 
  • 교착상태에 빠진 트랜잭션들을 강제 종료 시킴
    • 언두 로그 양이 적은 트랜잭션이 롤백 대상이 됨. (서버 부하 관점)
  • 잠금 목록 리스트에 새로운 잠금을 걸고 검사 (잠금 상태가 변경되지 않도록 )

 

시스템 변수
  • innodb_deadlock_detect: 데드락 감지 스레드 동작 여부
  • innodb_table_locks: 테이블 레벨의 잠금까지 감지하는지 여부
  • innodb_lock_wait_timeout: 데드락 상황에서 일정 시간이 지나면 에러나도록 타임아웃 시간 설정 (요청 실패 + 에러 메시지)

 

자동화된 장애 복구

  • 예기치 못한 종료로 인한 데이터 복구 작업이 자동으로 진행됩니다.
    • 완료되지 못한 트랜잭션
    • 디스크에 데이터 일부만 기록된 페이지
  • (기본) 서버가 시작될 때 자동 복구를 수행

 

innodb_force_recovery (시스템 변수)

  • 파일의 손상 여부 검사 활성화 (데이터 파일, 로그 파일)
  • SELECT 이외의 쿼리는 수행할 수 없습니다.

 

복구 모드 수준
  • 1: 데이터나 인덱스 페이지에서 손상된 부분이 발견되도 무시 + 서버 재시작 (Database page corruption on disk or a failed)
  • 2: 백그라운드 스레드의 메인 스레드 작업 수행 X + 서버 재시작
  • 3: 커밋되지 않고 종료된 트랜잭션 롤백 X
  • 4: 인덱스 변경작업은 인서트 버퍼에 남아 있는데, 이 부분에 이상이 감지되더라도 재시작한다 (데이터 변경으로 인한)
  • 5: 언두 레코드, 리두 레코드 사용 X + 재시작 (비정상적으로 종료된 트랜잭션의 상태를 재현하기 위한)
  • 6: 리두 로그가 손상되더라도 재시작

 

InnoDB Buffer Pool

  • 디스크의 데이터 파일이나 인덱스 정보를 메모리에 캐시해두는 공간입니다.
  • 쓰기 작업을 지연시켜 일괄 작업으로 처리할 수 있게 해주는 버퍼 역할도 같이 합니다.

 

크기 설정
  • 레코드 버퍼
    • 각 클라이언트 세션에서 테이블의 레코드를 읽고 쓸 때 버퍼로 사용하는 공간
    • 전체 커넥션 개수와 각 커넥션에서 읽고 쓰는 테이블의 개수에 따라 결정됩니다.
    • 동적으로 해제되기도 하므로 정확한 크기를 측정할 수 없습니다.
  • 청크 단위로 쪼개어 관리됩니다.
    • 내부적으로 128MB 로 나뉩니다.
    • 내부 잠금 경합을 줄이기 위함입니다.
  • 시스템 변수
    • innodb_buffer_pool_size : 동적 변수로, 버퍼 풀 사이즈를 의미합니다.
    • innodb_buffer_pool_instances : 버퍼 풀을 여러 개로 관리할 수 있습니다. (기본 8개)(버퍼 사이즈가 1GB 이하면 1개)

 

구조
  • 페이지 크기 조각으로 관리합니다
  • 3개의 자료구조로 관리합니다.
    • LRU 리스트 : 디스크로부터 한번 읽어온 페이지를 최대한 메모리에 오래 유지해서 읽기를 최소화하는 것
    • 프리 리스트 : 비어있는 페이지들의 목록. 디스크의 데이터 페이지를 읽어와야 하는 경우 사용됩니다.
    • 플러시 리스트 : 디스크로 동기화되지 않은 데이터를 가진 데이터 페이지(더티 페이지)의 목록입니다.

 

데이터 찾는 과정
  • 필요한 레코드의 데이터 페이지가 버퍼 풀에 존재하는지 검사
    • InnoDB Adaptive Hash Index를 이용해 페이지를 검색
    • 인덱스를 이용해 페이지 검색
  • 디스크에서 필요한 데이터 페이지를 버퍼 풀에 적재
  • 버퍼 풀의 LRU 헤더 부분에 적재된 데이터 페이지가 실제로 읽히면 MRU 헤더 부분으로 이동
  • 버퍼 풀에 사주하는 데이터 페이지는 얼마나 최근에 접속했는지에 따라 나이가 부여되며 오랫동안 사용되지 않으면 제거된다
    • 쿼리에 의해 재사용되면 나이가 초기화가 되고 MRU 헤더부분으로 옮겨진다.
  • 필요한 데이터가 자주 접근됬다면 해당 페이지의 인덱스 키를 Adaptive Hash Index에 추가합니다.

 

페이지
  • 클린 페이지 : 디스크에서 읽은 페이지 입니다.
  • 더티 페이지 : 디스크에 반영되지 않고 INSERT, DELETE, UPDATE 쿼리로 변경된 데이터를 가진 페이지 입니다.

 

리두 로그
  • 쓰기 버퍼링 기능에 쓰입니다.
  • 1개 이상의 고정 크기 파일을 연결해서 순환 고리처럼 사용합니다.
    • 매번 기록될 때마다 로그 포지션은 증가합니다.
    • 이를 LSN(Log Sequence Number) 라 합니다.
  • 재사용 가능한 공간과 당장 재사용이 불가능한 공간(Active Redo Log)으로 구분하여 관리합니다.
    • 활성 리두 공간은 더티 페이지와 연관된 로그입니다.
  • 체크 포인트
    • 더티 페이지를 디스크로 동기화하는 시점
    • 더티 페이지는 언젠가 디스크로 기록되야 합니다.
    • 더티 페이지는 특정 리두 로그 엔트리와 관계를 가지고 있습니다.
    • 체크 포인트가 발생하면 체크포인트 LSN보다 작은 리두 로그 엔트리와 관련된 더티 페이지는 모두 디스크로 동기화 됩니다
  • 체크포인트 에이지
    • 가장 최근의 체크포인트 LSN과 마지막 리두 로그 엔트리의 LSN 차이를 가리킵니다.
    • 마지막 체크포인트 이후 남은 데이터 양을 나타냅니다.
    • 활성 리두 공간의 크기를 의미합니다.

 

플러시
  • 더티 페이지들의 디스크 플러시 기능을 백그라운드로 수행합니다.
  • 플러시 리스트 플러시
    • 공간 재활용을 위해 오래된 로그 엔트리 공간을 비워야 합니다.
      • 이를 위해 로그 엔트리의 더티 페이지를 디스크로 동기화 합니다.
    • 시스템 변수
      • innodb_page_cleaners : 더티 페이지를 디스크로 동기화 하는 클리너 스레드의 개수 (한 개당 버퍼 풀 인스턴스 담당)
      • innodb_max_dirty_pages_pct : 버퍼 풀의 더티 페이지 비율
      • innodb_max_dirty_pages_pct_lwm : 일정 수준 이상의 더티 페이지가 발생하면 조금씩 디스크로 기록하기 위한 기준
      • innodb_io_capacity : 어느정도 더티 페이지 읽고 쓰기가 가능한지 설정
      • innodb_io_capacity_max : (디스크가 최대의 성능을 발휘할 때) 어느정도 더티 페이지 읽고 쓰기가 가능한지 설정
      • innodb_adaptive_flushing : 어댑티브 플러시 기능 활성화 (리두 로그 증가 속도를 분석해서 적절하게 더티 페이지 유지)
      • innodb_adaptive_flushing_lwm : 어댑티브 플러시 알고리즘 작동 기준 (활성 리두 로그 공간 점유 비율)
      • innodb_flush_neighbors : 더티 페이지를 디스크에 기록할 때 근접한 페이지 중에 더티 페이지가 있다면 같이 기록
  • LRU 리스트 플러시
    • 사용 빈도가 낮은 데이터 페이지들을 제거하서 새로운 페이지들을 읽어오는 기능
    • 시스템 변수
      • innodb_lru_scan_depth : LRU 리스트의 끝부분부터 시작해서 설정된 개수만큼 페이지를 스캔

 

상태 백업 및 복구
  • 워밍업
    • 디스크의 데이터가 버퍼 풀에 적재돼 있는 상태
    • 워밍업 된 상태에서 성능이 잘 나옵니다.
  • 상태 백업 및 복구
    • 파일
      • ib_buffer_pool : LRU 리스트에서 적재된 데이터 페이지의 메타 정보만 가져와서 저장합니다.
    • 시스템 변수
      • innodb_buffer_pool_dump_now : 워밍업을 위해 현재 버퍼 풀의 상태 백업하기
      • innodb_buffer_pool_load_now : 백업된 버퍼 풀의 상태 복구하기
      • innodb_buffer_pool_load_abort : 백업 중 복구 작업을 중단하고자 하는 경우 켜기
      • innodb_buffer_pool_load_at_startup : 버퍼 풀 백업 자동화
      • innodb_buffer_pool_dump_at_shutdown : 버퍼 풀 복구 자동화
    • 상태 변수
      • innodb_buffer_pool_dump_status : 복구 과정에서 어느정도 진행됐는지 확인

 

적재 내용 확인
  • information_schema.innodb_buffer_page : 버퍼 풀의 페이지 정보를 확인할 수 있습니다.
  • information_schema.innodb_cached_indexes : 인덱스별 페이지가 얼마나 버퍼 풀에 적재돼 있는지 확인할 수 있습니다.

 

Double Write Buffer

리두 로그
  • 공간의 낭비를 막기 위해 페이지의 변경된 내용만 기록합니다.

 

파셜 페이지
  • 변경 내용만 기록하기 때문에 페이지의 일부만 기록되는 문제가 발생할 수 있습니다.
  • 이를 막기 위해 Double-Write 기법을 사용합니다.

 

Double-Write
  • 페이지가 기록되는 도중 실패할 경우 백업의 목적으로 사용됩니다.
  • 페이지 기록 과정
    • 더티 페이지를 묶어 한번의 디스크 쓰기로 Double-Write 버퍼에 기록합니다.
    • 각 더티 페이지를 파일의 적당한 위치에 하나씩 랜덤으로 쓰기를 실행합니다.
  • 시스템 변수
    • innodb_doublewrite : Double-Write 기능 사용 여부를 활성화 합니다.
    • innodb_flush_log_at_trx_commit : 리두 로그 동기화 설정을 활성화 합니다.

 

언두 로그

  • 트랜잭션과 격리 수준을 보장하기 위해 DML로 변경되기 이전 버전의 데이터를 별도로 백업합니다.
  • 트랜잭션의 롤백과 격리 수준을 보장합니다.

 

트랜잭션의 격리 수준
  • 동시에 여러 트랜잭션이 데이터를 변경하거나 조회할 떄 한 트랜잭션의 작업 내용이 다른 트랜잭션에 어떻게 보일지를 결정하는 기준
  • 현재 트랜잭션 종료 전까지 데이터의 관련 트랜잭션들의 언두 로그는 삭제되지 않습니다.

 

레코드 모니터링
  • 쿼리 문장으로 데이터를 변경했을 때 변경 전의 데이터를 보관하는 곳 입니다.
  • 롤백하면 언두 영역의 백업된 데이터를 다시 데이터 파일로 복구합니다.
  • 언두 로그 레코드의 갯수가 많아질 수록 메모리 비용이 증가하여 성능이 떨어집니다.
  • 서버에서 레코드 건수를 확인할 수 있습니다.
SHOW ENGINE INNODB STATUS

 

언두 테이블 스페이스
  • 언두 로그가 저장되는 공간입니다.
  • 시스템 테이블 스페이스 외부의 별도 로그 파일에 기록됩니다.
  • 롤백 세그먼트 : 1개의 언두 테이블 스페이스는 128개 이하의 롤백 세그먼트를 가집니다.
    • 언두 슬롯 : 1개의 롤백 세그먼트는 (페이지 크기 / 16byte) 개의 언두 슬롯을 가집니다.
  • 공간 자르기 (자동 모드)
    • 트랜잭션이 데이터를 변경하면 언두 로그에 기록되고 트랜잭션이 커밋되면 언두 로그가 불필요해진다.
    • 언두 퍼지 : 퍼지 스레드는 주기적으로 깨어나 불필요해진 언두 로그를 삭제하는 작업을 수행한다
    • innodb_undo_log_truncate : 언두 퍼지를 활성화 여부를 의미한다.
    • innodb_purge_resg_truncate_frequency : 언두 퍼지를 빈번하게 하는 정도를 의미한다.
SELECT TABLESPACE_NAME, FILE_NAME FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE LIKE 'UNDO LOG';

 

리두 로그 및 로그 버퍼

  • 트랜잭션의 영속성을 보장하게 해주는 기능입니다.
  • 예기치 못하게 서버가 종료되었을 경우 데이터 파일에 기록되지 못한 데이터를 잃지 않게 해주는 안전장치 입니다.

 

복구
  • 커밋됬지만 데이터 파일에 기록되지 않은 경우
    • 리두 로그의 내용을 가져와 데이터 파일에 복사합니다.
  • 롤백됬지만 데이터 파일에 이미 기록된 데이터
    • 언두 로그의 내용을 가져와 데이터 파일에 복사합니다.

 

쓰기 작업
  • 먼저 리두 로그에 기록합니다.
  • 쓰기 비용을 줄이기 위해 리두 로그 자료구조를 활용합니다.

 

시스템 변수
  • innodb_flush_log_at_trx_commit : 리두 로그를 어느 주기로 디스크에 동기화할지 결정하는 변수
  • innodb_log_file_size : 리두 로그 파일의 크기를 결정합니다.
  • innodb_log_files_in_group : 리두 로그 파일의 개수를 결정합니다.

 

로그 버퍼
  • 리두 로그 버퍼링에 사용되는 메모리 공간입니다.
  • 서버가 빈번한 디스크 I/O를 피하게 해주며 전체적인 성능을 향상시킵니다.
  • 일정 크기에 도달하거나 트랜잭션이 일어나면 리두 로그 파일에 쓰여집니다.
  • 기본적으로 16MB로 설정되어 있습니다.

 

리두 로그 아카이빙
DO innodb_redo_log_archive_start('backup', '20200722');
DO innodb_redo_log_archive_stop();
  • innodb_redo_log_archive_dirs : 리두 로그가 저장될 디렉터리를 지정합니다.

 

리두 로그 활성화 및 비활성화
ALTER INSTANCE ENABLE INNODB REDO_LOG;
ALTER INSTANCE DISABLE INNODB REDO_LOG;
  • (status) innodb_redo_log_enabled : 리두 로그 활성화 여부를 뜻합니다.

 

어댑티브 해시 인덱스

  • 인덱스의 B-Tree 검색 시간을 줄여주기 위해 도입된 기능입니다.
  • InnoDB 스토리지 엔진에서 사용자가 자주 요청하는 데이터에 대해 자동으로 생성하는 인덱스 입니다.
  • 페이지의 키 값을 이용해 해시 인덱스를 만들고 즉시 찾아갈 수 있습니다.

 

해시 인덱스
  • 인덱스 키값과 해당 인덱스 키 값이 저장된 데이터 페이지 주소의 쌍으로 관리됩니다.
  • 인덱스 키
    • B-Tree 인덱스의 고유번호와 B-Tree 인덱스의 실제 키 값 조합으로 생성된다
  • innodb_adaptive_hash_index : 어댑티브 해시 인덱스 자동 생성의 활성화 여부 입니다.

 

 

출처