[ MySQL ] InnoDB

Manx·2023년 9월 17일
0

DBMS

목록 보기
5/8

InnoDB

  • MySQL 스토리지 엔진 중 하나.
  • 스토리지 엔진 중 거의 유일하게 레코드 기반의 잠금 제공한다.
    • 높은 동시성 처리가 가능하고 안정적이며 성능이 뛰어나다.

PK에 의한 클러스터링

  • PK를 기준으로 클러스터링되어 저장
  • PK 값의 순서대로 디스크에 저장
  • 세컨더리 인덱스는 레코드의 주소 대신 PK를 논리적인 주소로 사용
  • PK가 클러스터링 인덱스이기 떄문에 PK를 이용한 Range Scan은 빠르게처리된다.
  • 실행 계획에서 PK는 다른 보조 인덱스에 비해 비중이 높게 설정된다.

MVCC

  • 잠금을 사용하지 않는 일관된 읽기를 제공
  • Undo log를 이용해 이 기능을 구현

업데이트 과정

  • Undo 로그에 원본 저장 후 InnoDB 버퍼 풀의 데이터를 업데이트
  • 격리 수준에 따라 어느 영역에 있는 데이터를 읽을지 결정
  • READ_COMMITED 이상 ⇒ Undo 영역



자동 데드락 감지

  • InnoDB는 잠금이 교착 상태에 빠지지 않았는지 체크하기 위해
    잠금 대기 목록그래프(Wait-for-List)형태로 관리한다.
  • 데드락 감지 스레드를 가지고 있어, 주기적으로 그래프를 검사해 교착 상태에 빠진 트랜잭션들을 찾아서 그 중 하나를 강제 종료한다.
  • 종료될 쓰레드를 판단하는 기준은 Undo Log 양이며,
    Undo Log 레코드를 더 적게 가진 트랜잭션이 일반적으로 롤백의 대상이 된다.
    • 롤백을 해도 Undo 처리를 해야 할 내용이 적으며, 부하도 덜 유발한다.
  • InnoDB에서는 MySQl 엔진에서 관리되는 테이블 잠금을 볼 수가 없어
    Dead Lock 감지가 불확실할 수 있다.
    • innodb_table_locks 을 활성화하면, 테이블 레벨의 잠금까지 감지할 수 있다.
  • Dead Lock을 감지할 때, 잠금 상태가 변경되지 않도록 잠금 테이블에
    새로운 잠금을 걸고 데드락 스레드를 찾게 된다.
    이때 작업 중이던 스레드는 더는 작업을 진행하지 못해 서비스에 악영향을 미칠 수 있다.
  • innodb_deadlock_detect 를 OFF하면, Dead Lock 감지 스레드는 작동하지 않는다.
  • innodb_lock_wati_timeout 을 설정하면, 자동으로 요청을 실패하게 된다.

💡 Dead Lock 감지 스레드가 부담되어 OFF할 경우, timeout을 50초보다 훨씬 낮은 시간으로 사용하라


InnoDB 버퍼 풀

용도

  • 데이터 캐시
  • 쓰기 지연

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

버퍼 풀 크기 설정

  • 레코드 버퍼가 상당한 메모리를 사용하기도 한다.
    • 클라이언트 세션에서 테이블의 레코드를 읽고 쓸 때 버퍼로 사용하는 공간
    • Connection이 많고 사용하는 테이블도 많으면 용량이 커질 수 있다.
  • 5.7버전 부터 InnoDB 버퍼 풀의 크기를 동적으로 조절할 수 있게 되었다.
  • 작은 값으로 설정해서 증가시켜 가는 방법이 최적이다.
  • 메모리가 8GB 미만이라면, 50%를 InnoDB 버퍼 풀로 설정하는 것이 좋다.
  • innodb_buffer_pool_size

버퍼 풀 구조

  • 메모리 공간을 페이지 크기의 조각으로 쪼개어 InnoDB 스토리지 엔진이 데이터를 필요로 할 때 해당 데이터 페이지를 읽어서 각 조각에 저장한다.
  • 크기 조각을 관리하기 위해 LRU, Flush, Free 3개의 자료 구조를 관리한다.
  • Free List : 실제 사용자 데이터로 채워지지 않은 비어 있는 페이지 목록
  • 플러시 리스트
    • 디스크로 동기화되지 않은 데이터를 가진 데이터 페이지의
      변경 시점 기준의 페이지 목록
    • 읽은 후 변경이 없다면 플러시 리스트에 관리되지 않지만, 변경이 가해진 데이터 페이지는 플러시 리스트에 관리된다.
    • Redo Log → 디스크, 데이터 페이지가 디스크로 기록됐다는 것은 보장 X
      • 체크포인트를 발생시켜 Redo Log와 데이터 페이지의 상태를 동기화
      • 체크포인트는 Redo Log의 어느 부분부터 복구를 실행해야 할지 판단하는 기준점

LRU 캐시 전략

변형된 LRU( Least Recently Used Algorithm ) 사용

  • 가장 오랫동안 참조되지 않은 페이지 제거

기존

  • Head에 가장 최신, Tail에 오래된 데이터 ⇒ 후에 Tail 제거

MySQL

  • New, Old의 Sublist로 나눠지며 각 각 Head와 Tail 존재
  • New의 Tail과 Old의 Head가 만나는 지점을 Mid Point
    • 새로운 페이지가 들어올 경우 Old의 Head에 저장

단순한 LRU구조의 경우 Where절 없는 Select와 같은 일회성 데이터를 가져올 경우 자주 사용되던 페이지가 제거될 수 있다.

  • Old의 Head로 이동하면, 사용되지 않을 경우 빠르게 버퍼 풀에서 제거된다.
  • 다시 참조될 경우 New의 head로 이동시켜 보관한다.



버퍼 풀과 Redo Log

  • 버퍼 풀은 데이터 캐시쓰기 버퍼링이라는 두 가지 용도가 있다.

  • 단순히 메모리 공간을 늘리는 것은 데이터 캐시 기능만 향상시킨다.

  • 쓰기 버퍼링 기능을 향상시키기 위해서는 리두 로그와의 관계를 파악해야 한다.

  • 변경되지 않은 클린 페이지와 변경된 데이터를 가진 더티 페이지도 가지고 있다.

    • 더티 페이지는 언젠가는 디스크에 기록돼야 한다.
  • Redo Log는 고정 크기 파일을 연결해서 순환 고리처럼 사용한다.

    • 데이터 변경이 계속 발생하면 Redo Log 파일에 다시 새로운 로그 엔트리로 덮어 쓰인다.
    • 재사용 가능한 공간과 당장 재사용 불가능한 공간을 구분해 관리해야 한다.
    • 재사용 불가능한 공간을 활성 리두 로그(Active Redo Log) 라고 부른다.
  • Redo Log File의 공간은 매번 기록될 때마다 로그 포지션은 계속 증가된 값을 갖는다.

    ⇒ LSN (Log Sequence Number)

  • 주기적으로 체크포인트 이벤트를 발생시켜 Redo Log와 버퍼 풀의 더티 페이지를 디스크로 동기화

    • 가장 최근 체크포인트 지점의 LSN이 활성 리두 로그 공간의 시작점
    • 최근 체크포인트의 LSN과 마지막 Redo Log 엔트리의 LSN 차이를 Checkpoint Age라고 한다.
    • Checkpoint Age는 Active Redo Log 공간의 크기이다.
  • 버퍼 풀에 더티 페이지의 비율이 너무 높은 상태에서 갑자기 버퍼 풀이 필요해지는 상황이 오면 매우 많은 더티 페이지를 한 번에 기록해야 하는 상황이 온다.

  • 버퍼 풀의 크기가 100GB 이하의 서버에서는 Redo Log File의 전체 크기를 대략 5~10GB 수준으로 선택하고 필요할 때마다 조금씩 늘려가면서 최적값을 선택하는 것이 좋다.



버퍼풀 상태 백업 및 복구

  • 디스크의 데이터가 버퍼 풀에 적재되지 않았을 경우 몇십 배의 쿼리 속도가 차이난다.
  • 5.5 버전에서는 강제 워밍업을 위해 주요 테이블과 인덱스에 대해 풀 스캔을 한 번씩 실행하고 서비스를 오픈했었다.
  • 5.6 버전부터는 버퍼 풀 덤프 및 적재 기능이 도입됐다.
  • innodb_buffer_pool_dump_now 를 이용해 현재 버퍼 풀의 상태를 백업할 수 있다.
    • innodb_buffer_pool_load_now ⇒ 복구
  • 자동으로 하는 방법 innodb_buffer_pool_dump_at_shutdown,innodb_buffer_pool_load_at_startup
profile
백엔드 개발자

0개의 댓글