모종닷컴

MySQL InnoDB 스토리지 엔진 (2) 본문

Programming/데이터베이스

MySQL InnoDB 스토리지 엔진 (2)

모종 2022. 8. 8. 23:40
반응형

버퍼 풀

  • InnoDB 스토리지 엔진의 핵심적인 부분이다.
  • 디스크의 데이터 파일이나 인덱스 정보를 메모리에 캐시해 두는 공간. 쓰기 작업을 지연시켜 일괄 작업으로 처리할 수 있게 해주는 버퍼 역할도 같이 한다. => 디스크 작업의 횟수를 줄일 수 있다. 

버퍼 풀 사이즈 

  • 운영체제와 클라이언트 스레드가 사용할 메모리를 고려하여 설정해야 한다.
  • 클라이언트 세션에서 테이블의 레코드를 읽고 쓸 때 버퍼로 사용하는 공간을 '레코드 버퍼'라고 하는데, 커넥션이 많고 사용하는 테이블도 많다면 레코드 버퍼 용도로 사용되는 공간이 많이 필요해질 수 있다. 하지만 레코드 버퍼 공간은 별도로 설정할 수 없으며, 전체 커넥션 수와 커넥션에서 읽고 쓰는 테이블의 개수를 가늠할 수 없으므로 정확한 메모리 공간 산정이 어렵다.
  • 위에서 메모리 산정이 어렵다고 했는데 MySQL 5.7 버전부터 버퍼 풀의 크기를 동적으로 조절할 수 있게 개선되었다. 
    • 버퍼 풀의 크기를 작은 값으로 설정하고 조금씩 상황을 봐 가면서 증가시키는 방법이 최적이다.
    • 버퍼 풀의 크기 변경은 크리티컬한 변경이므로 서버가 한가한 시점을 골라서 진행해야 한다.
    • 버퍼 풀의 크기를 줄이는 작업은 서비스 영향도가 매우 크므로 가능하면 버퍼 풀의 크기를 줄이는 작업은 하지 않도록 주의해야 한다.
  • 버퍼 풀은 전체를 관리하는 잠금(세마포어)으로 인해 내부 잠금 경합을 많이 유발해왔는데, 이런 경합을 줄이기 위해 버퍼 풀을 여러 개로 쪼개어 관리할 수 있게 개선되었다.

버퍼 풀의 구조

  • InnoDB 스토리지 엔진은 버퍼 풀이라는 거대한 메모리 공간을 페이지 크기의 조각으로 쪼개어 InnoDB 스토리지 엔진이 데이터를 필요로 할 때 해당 데이터 페이지를 읽어서 각 조각에 저장한다.
  • 버퍼 풀의 페이지 크기 조각을 관리하기 위해 LRU(Least Recentry Used) 리스트, Flush 리스트, Free 리스트라는 3개의 자료 구조를 관리한다.
    • Free 리스트 : 버퍼 풀에서 실제 사용자 데이터로 채워지지 않은 비어 있는 페이지들의 목록. 사용자의 쿼리가 새롭게 디스크의 데이터 페이지를 읽어와야 하는 경우 사용.
    • Flush 리스트 : 디스크로 동기화되지 않은 데이터 페이지(= 더티 페이지)의 변경 시점 기준의 페이지 목록을 관리. 데이터가 변경되면 InnoDB는 변경 내용을 리두 로그에 기록하고 버퍼 풀의 데이터 페이지에도 변경을 내용을 반영한다. 리두 로그의 각 엔트리는 특정 데이터 페이지와 연결된다. 데이터 변경이 가해진 데이터 페이지는 플러시 리스트에 관리되고 특정 시점이 되면 디스크로 기록.
    • LRU 리스트 : 디스크로부터 한 번 읽어온 페이지를 최대한 오랫동안 InnoDB 버퍼 풀의 메모리에 유지해서 디스크 읽기는 최소화한다.

버퍼 풀과 리두 로그

  • 상단 Flush 리스트에서 설명했듯이 리두 로그와 더티 페이지는 관계가 있다.
  • InnoDB의 더티 페이지(CUD 명령으로 변경된 페이지)는 언젠가는 디스크로 기록돼야 한다.
  • InnoDB 스토리지 엔진에서 리두 로그는 1개 이상의 고정 크기 파일을 연결해서 순환 고리처럼 사용한다.
  • 데이터 변경이 계속 발생하면 리두 로그 파일에 기록됐던 로그 엔트리는 다시 새로운 로그 엔트리로 덮어 쓰인다.
  • 전체 리두 로그 파일에서 재사용 가능한 공간과 당장 재사용 불가능한 공간을 구분해서 관리해야 하는데, 재사용 불가능한 공간을 활성 리두 로그라고 한다. 그리고 리두 로그 공간 중 더티 페이지를 가리키고 있는 곳이 이 활성 리두 로그다.
  • 리두 로그 파일의 공간은 순환되어 사용되고 기록될 때마다 로그 포지션은 계속 증가된 값(LSN : Log Sequence Number)을 갖는다.
  • InnoDB 스토리지 엔진은 주기적으로 체크포인트 이벤트를 발생시켜 리두 로그와 버퍼 풀의 더티 페이지를 디스크로 동기화시킨다.
  • 체크포인트가 발생하면 체크포인트 LSN보다 작은 리두 로그 엔트리와 관련된 더티 페이지는 모두 디스크로 동기화해야 한다. 

버퍼 풀 플러시

MySQL 5.6 버전까지는 InnoDB 스토리지 더티 페이지 플러시 기능이 그다지 부드럽게 처리되지 않았다. 급작스럽게 디스크 기록이 폭증해서  MySQL 서버의 사용자 쿼리 처리 성능에 영향을 받는 경우가 많았다. MySQL 5.7 버전에서는 개선되면서 이러한 디스크 쓰기 폭증 현상은 발생하지 않았다.

InnoDB 스토리지 엔진은 버퍼 풀에서 아직 디스크로 기록되지 않은 더티 페이지들을 성능상의 악영향 없이 디스크에 동기화하기 위해 2개의 플러시 기능을 백그라운드로 실행한다.

Flush 리스트 플러시

위에서 리두 로그 공간의 재활용을 위해 주기적으로 더티 페이지와 함께 오래된 리두 로그 엔트리를 동기화해야 한다고 설명했다. 그래서 InnoDB 스토리지 엔진은 주기적으로 플러시 리스트 플러시 함수를 호출해서 플러시 리스트에서 오래전에 변경된 데이터 페이지 순서대로 디스크에 동기화하는 작업을 수행한다. 그리고 이 작업에서 얼마나 많은 더티 페이지를 디스크에 동기화하는 양에 따라 사용자의 쿼리 처리가 영향을 받을 수도 있다. 이를 위해 InnoDB에서는 몇 가지 시스템 변수를 제공한다.

  • innodb_page_cleaners : 더티 페이지를 디스크로 동기화하는 클리너 스레드 개수 조정
  • innodb_max_dirty_pages_pct_lwn: 일정 수준 이상의 더티 페이지가 발생하면 조금씩 더티 페이지를 디스크로 기록
  • innodb_flush_neighbors : 더티 페이지를 디스크에 기록할 때 디스크에서 근접한 페이지 중에서 더티 페이지가 있다면 InnoDB 스토리지 엔진이 함께 묶어서 디스크로 기록하게 해주는 기능 

LRU 리스트 플러시

InnoDB 스토리지 엔진은 LRU 리스트에서 사용 빈도가 낮은 데이터 페이지들을 LRU 리스트 플러시 함수를 이용하여 페이지들을 제거해서 공간을 정리한다. innodb_lru_scan_depth 시스템 변수에 설정된 개수만큼의 페이지들을 끝부분부터 스캔하면서 더티 페이지는 디스크에 동기화하게 하며, 클린 페이지는 즉시 Free 리스트로 페이지를 옮긴다

반응형