Database/Mysql

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

noahkim_ 2023. 11. 24. 00:57

백은빈, 이성욱 님의 "Real MySQL" 책을 정리한 포스팅 입니다.

 

1. Architecture

기능

  • 잠금 (레코드 기반)

 

장점

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

 

2. 클러스터링

프라이머리 키 기준

  • 프라이머리 키는 다른 보조 인덱스에 비해 가중치가 높게 설정됨

 

3. 외래 키 지원

제약

슈퍼타입-서브타입
  • 서브타입 테이블에 슈퍼타입 테이블의 기본 키를 참조하는 외래 키 컬럼을 설정해야 함

 

잠금이 여러 테이블로 전파됨
  • 외래 키 제약이 활성화 되면 부모 테이블과 자식 테이블에 대해 잠금을 수행하게 됨
  • 자식 테이블에서 데이터를 업데이트 하거나 삭제할 때 부모 테이블도 잠김
  • 여러 테이블이 잠금 상태에 놓이게 되므로 데드락 발생 가능성이 발생함

 

foreign_key_checks

  • 참조 무결성 제약 원칙 활성화

 

OFF
  • 외래 키 관계의 부모 테이블에 대한 작업 무시
  • 참조 무결성은 유지되지 않음

 

3. MVCC (Multi Version Concurrency Control)

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

 

Non-Locking Consistent Reads

하나의 레코드에 대해 여러 버전으로 관리
  • 여러 트랜잭션이 동시에 실행될 때, 다른 트랜잭션의 데이터 변경을 신경 쓰지 않고 읽기 작업을 할 수 있음

 

가장 최신의 일관된 상태 제공
  • 직전 버전의 데이터 확인 (트랜잭션 시작 시점 기준)
  • Undo Log 활용
    • Undo Log는 데이터의 이전 버전들을 보관
    • 읽기 작업 시 변경 전의 데이터를 조회할 수 있음

 

UPDATE

Inno Buffer Pool
  • 갱신된 값을 메모리에 기록
  • 트랜잭션이 커밋되거나 롤백되기 전까지 메모리 상에 존재함

 

Undo Log
  • 데이터가 변경되기 전, 기존 값을 기록
  • 롤백할 경우, 데이터를 원래 상태로 되돌릴 수 있도록 함

 

Commit

Inno Buffer Pool 디스크 플러시
  • Buffer Pool에 저장된 갱신된 값을 디스크에 반영

 

Undo Log 값 초기화
  • Undo Log는 롤백을 위한 정보이므로, 커밋후에는 필요없게 됨
  • 디스크에 반영된 후 삭제됨

 

Rollback

  • Undo Log에 기록된 값을 사용하여 값을 복원

 

4. 자동 데드락 감지

잠금 대기 목록

그래프 형태
  • 각 트랜잭션의 잠금 사애를 그래프 형태로 관리
  • 이 그래프를 보고 서로 대기하는 루프가 발생되면, 데드락 감지 스레드가 개입하여 해결함

 

데드락 감지

데드락 감지 스레드
  • 이 스레드는 일정 주기마다 트랜잭션 상태를 확인하고, 데드락이 감지되면 강제 롤백을 수행함
  • 보통 Undo Log 크기가 작은 트랜잭션을 대상으로 롤백을 수행 (서버 부하 관점)

 

잠금 대기 목록
  • 어떤 트랜잭션이 어떤 자원을 기다리고 있는지 정리한 목록
  • 잠금 대기 목록을 확인하면서 트랜잭션 간의 교착 상태가 발생했는지 탐색 (순환 대기 검사)
  • 잠금 대기 목록을 분석하는 동안, 새로운 트랜잭션이 잠금 정보를 변경하지 못하도록 잠금 대기 목록 자체에 새로운 잠금을 걸고 검사함

 

시스템 변수

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

 

5. 자동화된 장애 복구

  • 서버가 예기치 않게 종료되었을 때 자동으로 데이터 복구 작업을 수행함
  • 서버가 시작될 때 자동 복구를 수행

 

장애 복구가 필요한 상황

데이터 파일 또는 로그 손상
트랜잭션 충돌
서버 강제 종료
  • 완료되지 못한 트랜잭션
  • 데이터 일부만 기록된 디스크 페이지

 

innodb_force_recovery 시스템 변수

  • 복구 모드를 설정하는 시스템 변수
  • 레벨이 높을수록 더 많은 보구 작업을 무시하고 서버를 강제로 시작할 수 있음
  • SELECT 이외의 쿼리는 수행할 수 없습니다.

 

복구 모드
  1. 데이터나 인덱스 페이지에서 손상된 부분이 발견되도 무시하고 서버 재시작
  2. 백그라운드 스레드가 실행되지 않도록 차단 후 서버 재시작 (체크포인트 작업, 리두 로그 플러시 비활성화)
  3. 비정상으로 종료된 트랜잭션 롤백하지 않고 서버 재시작 (일부 데이터의 손실될 가능성 고려)
  4. 인서트 버퍼에 데이터가 남아 있는데, 이 부분에 이상이 감지되더라도 재시작
  5. 언두 로그, 리두 로그 무시하고 서버 재시작 (데이터 무결성 보장이 어려움)
  6. 리두 로그가 손상되더라도 복구를 시도함 (데이터 무결성 보장 안됨)

 

6. InnoDB Buffer Pool

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

 

페이지

클린 페이지
  • 디스크에서 읽은 페이지 입니다.

 

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

 

레코드 버퍼

  • 각 클라이언트 세션에서 테이블의 레코드를 읽고 쓸 때 버퍼로 사용하는 공간

 

개수
  • 전체 커넥션 개수와 각 커넥션에서 읽고 쓰는 테이블의 개수에 따라 결정됩니다.

 

크기
  • 정확한 크기를 측정할 수 없습니다. (동적으로 해제되기도 하므로)
  • 청크 단위로 쪼개어 나뉩니다 (128MB)
  • 내부 잠금 경합을 줄이기 위함입니다.

 

시스템 변수
  • innodb_buffer_pool_size
    • 버퍼 풀 사이즈를 의미합니다.
    • 동적 변수 입니다.
  • innodb_buffer_pool_instances
    • 버퍼 풀을 여러 개로 관리할 수 있습니다.
    • 기본 8개
    • 버퍼 사이즈가 1GB 이하면 1개

 

구조

  • 페이지 크기 조각 단위로 관리합니다

 

프리 리스트
  • 비어 있는 페이지 목록
  • 디스크에서 데이터를 읽어와야 하는 경우 사용됩니다.

 

LRU 리스트
  • 한 번 읽은 데이터를 최대한 메모리에 유지해서 디스크 접근을 최소화함
  • 자주 쓰는 데이터는 MRU에 위치하고, 사용 빈도가 낮아지면 LRU 리스트 끝으로 이동해 삭제됨

 

플러시 리스트
  • 디스크에 아직 기록되지 않은 변경된 더티 페이지 목록
  • 언젠가 디스크에 저장되어야 함

 

검색 과정

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

 

워밍업

  • 자주 사용되는 데이터를 버퍼 풀에 적재해두는 과정
  • 디스크 i/o가 줄고 성능이 향상됩니다.

 

플러시

  • 디스크와 메모리 간의 데이터 동기화 작업을 의미함
  • 백그라운드에서 더티 페이지들의 디스크 플러시 기능을 수행

 

플러시 리스트 플러시
  • 로그 엔트리의 더티 페이지를 디스크로 동기화 합니다.
  • 디스크 공간을 재활용할 수 있게 함

 

LRU 리스트 플러시
  • 사용 빈도가 낮은 데이터 페이지들을 제거하고, 새로운 페이지들을 버퍼 풀에 읽어오는 기능

 

시스템 변수
  • innodb_page_cleaners: 더티 페이지를 디스크로 동기화 하는 클리너 스레드의 개수 (한 스레드 당 버퍼 풀 인스턴스 담당)
  • innodb_max_dirty_pages_pct: 버퍼 풀의 더티 페이지 비율
  • innodb_max_dirty_pages_pct_lwm: 일정 수준 이상의 더티 페이지가 발생하면 조금씩 디스크로 기록하기 위한 기준
  • innodb_io_capacity: 디스크 i/o 용량 설정 (시스템이 얼마나 많은 더티 페이지를 일고 쓸수 있는지 결정)
  • innodb_io_capacity_max: 디스크가 최대의 성능을 발휘할 때 어느정도 더티 페이지 읽고 쓰기가 가능한지 설정
  • innodb_adaptive_flushing: 어댑티브 플러시 기능 활성화 (리두 로그 증가 속도를 분석해서 적절하게 더티 페이지 유지)
  • innodb_adaptive_flushing_lwm : 어댑티브 플러시 알고리즘 작동 기준 (활성 리두 로그 공간 점유 비율)
  • innodb_flush_neighbors: 더티 페이지를 디스크에 기록할 때 근접한 페이지 중에 더티 페이지가 있다면 같이 기록
  • innodb_lru_scan_depth: LRU 리스트의 끝부분부터 시작해서 설정된 개수만큼 페이지를 스캔

 

Double-Write Buffer

데이터 무결성
  • 디스크에 데이터를 기록하는 도중, 시스템이 실패할 경우 데이터 손실을 방지하기 위해 사용됨
  • 리두 로그는 변경 내용만 기록하기 때문에 페이지의 일부만 기록되는 문제가 발생할 수 있습니다.

 

Double-Write
  • 디스크에 한번에 기록하지 않고 두번 기록하여, 시스템 실패 시 복구할 수 있게 함
  • 페이지에 기록되는 도중 실패할 경우 백업의 목적

 

페이지 기록 과정
  • 더티 페이지를 64개씩 묶어 Double-Write Buffer에 기록
  • Double-Write Buffer에서 디스크의 Double-Write 영역으로 일괄 기록
  • Double-Write 영역에 기록된 데이터를 각 테이블의 데이터 파일에 개별적으로 기록
  • 완료 후 Double-Write Buffer에서 해당 페이지 제거

 

시스템 변수
  • innodb_doublewrite: Double-Write 기능 사용 여부를 활성화
  • innodb_flush_log_at_trx_commit: 리두 로그 동기화 설정을 활성화 (리두 로그가 디스크에 동기화되는 시점을 알 수 있음)

 

Write Buffering

성능 최적화
  • 변경 사항을 즉시 디스크에 기록하는 대신, 먼저 리두 로그에 저장

 

고정 크기 순환 방식
  • 고정 크기 파일들을 연결해서 순환 고리처럼 사용 (기록될 때마다 로그 포지션 증가)
  • 리두 로그가 다 차면 처음부터 다시 덮어쓰는 방식으로 동작

 

LSN (Log Sequence Number)
  • 리두 로그에 기록될 떄마다 증가하는 일련번호
  • LSN을 기준으로 체크포인트와 활성 로그 공간을 관리

 

활성 리두 공간
  • 활성 리두 공간은 재사용 불가능한 공간으로, 더티 페이지와 연관된 로그입니다.
  • 재사용 가능한 공간과 당장 재사용이 불가능한 공간으로 구분하여 관리

 

체크 포인트
  • 더티 페이지를 디스크로 동기화하는 시점
    • 리두 로그가 가득 차면 체크포인트가 발생합니다
  • 체크 포인트가 발생 시
    • 체크포인트 LSN보다 작은 리두 로그 엔트리와 관련된 더티 페이지는 모두 디스크로 동기화 됩니다
    • 디스크로 기록된 데이터의 리두 로그 공간은 재사용 가능해집니다.

 

체크포인트 에이지
  • 가장 최근의 체크포인트 LSN과 마지막 리두 로그 엔트리의 LSN 차이를 가리킵니다.
  • 마지막 체크포인트 이후 남은 데이터 양을 나타냅니다.
  • 즉, 활성 리두 공간의 크기를 의미합니다.

 

백업 및 복구

  • 버퍼 풀의 데이터를 복원하거나 백업하는 기능
  • 시스템 재시작 후에도 이전의 성능 상태를 복구하는 데 유용함

 

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: 인덱스별로 버퍼 풀에 적재된 페이지 정보 확인

 

리두 로그

커밋된 변경 사항을 기록하는 로그 파일
  • 예기치 못하게 서버가 종료되었을 경우 데이터 파일에 기록되지 못한 데이터를 잃지 않게 해주는 안전장치 입니다.
  • 커밋됬지만 데이터 파일에 기록되지 않은 경우, 리두 로그의 내용을 가져와 데이터 파일에 복사합니다.

 

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

 

리두 로그 아카이빙
DO innodb_redo_log_archive_start('backup', '20200722');
DO innodb_redo_log_archive_stop();

 

리두 로그 활성화 및 비활성화
ALTER INSTANCE ENABLE INNODB REDO_LOG;
ALTER INSTANCE DISABLE INNODB REDO_LOG;

 

시스템 변수
  • innodb_flush_log_at_trx_commit: 리두 로그를 어느 주기로 디스크에 동기화할지 결정하는 변수
  • innodb_log_file_size: 리두 로그 파일의 크기를 결정합니다.
  • innodb_log_files_in_group: 리두 로그 파일의 개수를 결정합니다.
  • innodb_redo_log_archive_dirs : 리두 로그가 저장될 디렉터리를 지정합니다.
  • innodb_redo_log_enabled : 리두 로그 활성화 여부를 뜻합니다.

 

언두 로그

  • DML 실행 시, 변경되기 이전 데이터의 버전을 저장하는 공간

 

ROLLBACK
  • ROLLBACK 시, 언두 로그에 있는 데이터를 다시 데이터 파일로 복원
  • 현재 트랜잭션이 종료되기 전까지 관련 언두 로그는 삭제되지 않음
    • 언두 로그가 많아질수록 메모리 사용량이 증가하여 성능 저하 가능

 

트랜잭션의 격리 수준 보장
  • MVCC를 지원하여 격리수준을 보장함

 

레코드 모니터링
SHOW ENGINE INNODB STATUS

 

언두 테이블 스페이스
SELECT TABLESPACE_NAME, FILE_NAME FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE LIKE 'UNDO LOG';
  • 언두 로그가 저장되는 공간
    • 시스템 테이블 스페이스와 분리되어 별도의 로그 파일로 저장됨
  • 구성 요소
    • 롤백 세그먼트: 1개의 언두 테이블 스페이스는 128개 이하의 롤백 세그먼트를 가짐
    • 언두 슬롯: 1개의 롤백 세그먼트는 (페이지 크기 / 16byte) 개의 언두 슬롯을 가집니다.

 

언두 퍼지
  • 퍼지 스레드는 주기적으로 깨어나 불필요해진 언두 로그를 삭제하는 작업을 수행
  • 트랜잭션이 데이터를 변경하면 언두 로그에 기록되고 트랜잭션이 커밋되면 언두 로그가 불필요해짐

 

 시스템 변수
  • innodb_undo_log_truncate: 언두 퍼지를 활성화 여부를 의미한다.
  • innodb_purge_resg_truncate_frequency: 언두 퍼지를 빈번하게 하는 정도를 의미한다.

 

어댑티브 해시 인덱스

  • 사용자가 자주 요청하는 데이터에 대해 자동으로 생성하는 인덱스 입니다.
  • 인덱스의 B-Tree 검색 시간을 줄여주기 위해 도입된 기능입니다.
    • B-Tree 인덱스는 균형 트리 구조이므로 트리 깊이 만큼 노드를 탐색하는 비용이 발생함
    • 특정 키 값에 대한 검색이 자주 반복될 경우, B-Tree를 계속 탐색하는 것은 비효율적
    • 어댑티브 해시 인덱스를 사용하면 단위 시간으로 데이터를 찾을 수 있음
  • 페이지의 키 값을 이용해 해시 인덱스를 만들고 즉시 찾아갈 수 있습니다.

 

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

 

 

출처