InnoDB 구현 프로젝트 - 메타데이터 페이지 분석

Haiseong Jeong·2025년 7월 23일

innodb-java

목록 보기
3/3

서론

지난 글에서는 InnoDB가 데이터를 테이블스페이스(tablespace) → 세그먼트(segment) → 익스텐트(extent) → 페이지(page) 순의 계층 구조로 저장한다는 개념을 정리했다. 각 구성요소의 역할과 관계를 살펴봤지만, 이는 어디까지나 논리적인 구조일 뿐이다.

실제로 디스크에 어떤 페이지가 할당되었는지, 어떤 익스텐트가 사용 중인지 등은 메타데이터 페이지에 저장된다. InnoDB의 저장 구조와 내부 동작 방식을 깊이 이해하려면 이 메타데이터 페이지들을 반드시 살펴봐야 한다.

이번 글에서는 그 중에서도 핵심적인 시스템 페이지인 FSP_HDR, XDES, INODE 페이지의 구조와 역할을 분석한다.

읽기전에

본격적으로 메타데이터 페이지 구조를 보기 전에, 어떤 정보가 어디에서 어떻게 관리되는지 한 번 정리해보자.
아래는 계층별 메타데이터가 저장되는 위치와 관련 구조체를 키워드 중심으로 정리한 표다.

계층메타데이터 위치, 구조체
FilespaceFSP_HDR Page, FSP Header
SegmentINODE Page, INODE Entry
ExtentXDES Entry, FSP_HDR/XDES Page

InnoDB의 연결 리스트

InnoDB는 익스텐트와 세그먼트를 상태별로 효율적으로 관리하기 위해 이중 연결 리스트(Double Linked List)를 사용한다.
단순 포인터 배열이 아니라 List base node라는 구조체를 통해 관리되며, 여기엔 next, prev 포인터가 함께 포함된다.

연결 리스트를 사용하면 아래와 같은 장점이 있다:

  • 상태별 익스텐트 탐색이 빠르다
    • FREE, FREE_FRAG, FULL_FRAG 등의 리스트를 순회하며 빠르게 할당 대상 검색 가능함
  • 세그먼트 단위 공간 관리가 유연해진다
    • 익스텐트가 가득 차거나 비면, 해당 세그먼트의 리스트(FREE, NOT_FULL, FULL) 간에 손쉽게 이동시킬 수 있음

FSP_HDR Page (Filespace Header Page)

FSP_HDR Page는 항상 페이지 번호 0번에 위치하며, 테이블스페이스의 전역 메타데이터를 담고 있는 페이지다.
즉, 이 페이지는 테이블스페이스 전체를 관리하는 출발점이다.

이전 글에서 다룬 것처럼, 모든 InnoDB 페이지는 앞에 FIL Header, 뒤에 FIL Trailer가 공통적으로 붙는다.
FSP_HDR Page는 그 안에 FSP Header와 256개의 XDES Entry를 포함한다.

FSP Header

FSP Header는 테이블스페이스의 전반적인 상태를 나타내는 메타데이터 필드로 구성된다.
InnoDB가 어떤 페이지를 할당할지, 얼마나 공간이 남았는지, 세그먼트나 익스텐트를 어떻게 관리할지 등 대부분의 결정이 이 정보를 기반으로 이루어진다.

FSP Header의 필드는 다음과 같다.

필드설명
Space ID테이블스페이스 고유 식별자
File size현재 파일에 존재하는 가장 큰 페이지 번호
Free limit초기화된 마지막 페이지 번호
Flags압축 여부 등 다양한 설정 값
FREE_FRAG 사용 페이지 수조각 페이지 공간 상태 추적
XDES List base nodes익스텐트 상태별 연결 리스트 헤더들
Next Unused Segment ID다음 세그먼트 할당 시 사용할 ID
INODE List base nodes세그먼트(INODE) 상태별 연결 리스트 헤더들

File size & free limit

File size는 테이블스페이스가 지금까지 확장된 최대 페이지 번호다.
하지만 확장됐다고 해서 그 페이지들이 다 초기화돼서 쓸 수 있는 상태인 건 아니다.

실제로 쓸 수 있을 정도로 초기화까지 완료된 마지막 페이지 번호가 Free limit이다.
이 두 값은 새로운 데이터를 저장할 공간이 필요할 때, InnoDB가 파일을 더 확장할지 말지 판단하는 기준이 된다.

  1. Free limit < File size인 경우
    • 파일은 물리적으로 확장되었으나 아직 초기화 되지 않는 페이지가 있음
    • Free limit 다음 번호부터 순차적으로 페이지를 초기화한다.
  2. Free limit == File size인 경우
    • 초기화된 공간이 모두 사용되었고 더 이상 쓸 수 있는 공간이 없음
    • 물리적인 파일의 크기를 확장시킴

XDES Entry를 연결하는 List base node & FREE_FRAG 사용 페이지 수

XDES Entry는 익스텐트(Extent)의 상태를 나타내는 구조체인데, 이들을 서로 연결하는 리스트들이 존재한다.
FSP Header는 각 상태별로 아래와 같은 리스트의 시작 지점을 갖고 있다.

  • FREE: 아예 사용되지 않은 익스텐트
  • FREE_FRAG: 일부 페이지만 조각 단위로 사용된 익스텐트
  • FULL_FRAG: 더 이상 조각 단위로도 공간이 없는 익스텐트

이 리스트를 따라가면서 InnoDB는 어떤 익스텐트를 공간 할당에 쓸지 판단할 수 있다.

FREE_FRAG 사용 페이지 수는 무엇일까?
FSP Header에는 FREE_FRAG 상태인 익스텐트의 사용 가능한 페이지 수가 별도로 캐싱된다.

리스트를 순회하면서 "여유 페이지 몇 개 남았지?"를 매번 확인하는 건 느릴 수밖에 없다.
FSP Header에 미리 값이 캐싱돼 있다면 빠르게 조건을 판단하고 바로 할당 여부를 결정할 수 있다.

종합해보면 공간을 할당하는 로직은 다음과 같다.

  1. FREE_FRAG 리스트 확인
    • 조각 단위로 페이지를 할당할 수 있는 익스텐트가 있으면 바로 사용
    • 이때 사용 가능한 페이지 수 캐시도 함께 확인
  2. FREE 리스트 확인
    • 조각으로도 안 되고 익스텐트 전체가 필요할 경우, FREE 상태인 익스텐트에서 새로 할당
  3. 두 리스트 모두 부족하면?
    • File size와 Free limit을 비교해서 아직 초기화되지 않은 페이지가 있는지 확인
      • 있다면 → 페이지 초기화 진행
      • 없다면 → 테이블스페이스 확장

XDES Entry

각 XDES Entry는 하나의 Extent(64 페이지)에 대한 메타데이터를 담고 있으며, 해당 익스텐트의 상태를 관리한다.

필드설명
Segment ID해당 익스텐트를 사용하는 세그먼트의 ID
List Node이중 연결 리스트를 위한 포인터 (prev/next)
State익스텐트의 상태를 나타냄. FREE, FREE_FRAG, FULL_FRAG, FSEG 중 하나
Page Bitmap각 페이지 정보를 2비트에 담음 (64개 페이지 × 2비트 = 총 128bit)

State

State는 익스텐트가 어떤 상태에 있는지를 나타낸다. 각 상태는 다음과 같은 의미를 가진다

  • FREE : 아무 세그먼트에도 속하지 않고, 어떤 페이지도 사용되지 않은 익스텐트. 새 세그먼트나 익스텐트 단위 할당에 사용될 수 있다.
  • FREE_FRAG : 세그먼트에 속해 있고 일부 페이지만 사용 중인 익스텐트. 조각 할당(fragmented allocation)에 사용된다. 남은 페이지를 계속해서 채워나갈 수 있다.
  • FULL_FRAG : 세그먼트에 속해 있지만 모든 페이지가 사용된 상태. 더 이상 조각 단위로 할당할 수 없다.
  • FSEG : 익스텐트 전체가 세그먼트에 통째로 할당된 상태. 조각 단위가 아닌, 인덱스 페이지 등으로 통으로 쓰이는 경우에 해당된다.

그런데 FSP Header에 FSEG 상태 리스트는 왜 없을까?

FREE, FREE_FRAG, FULL_FRAG 상태의 익스텐트는 각각 전역적으로 관리되는 이중 연결 리스트를 통해 연결되어 있다.
FSEG 상태인 익스텐트는 세그먼트가 통째로 소유하고 있는 익스텐트이기 때문에, 전역 리스트로 연결할 필요가 없다.

세그먼트와 세그먼트가 소유하는 익스텐트들을 자신만의 리스트(FREE, NOT_FULL, FULL)로 관리하는 주체는 INODE Entry인데 이건 뒷쪽에서 다룬다.

테이블이 커지면?

FSP_HDR에는 최대 256개의 XDES Entry를 저장할 수 있다.
즉, 하나의 FSP_HDR 페이지는 총 256개 익스텐트(= 16,384 페이지 = 256MB)까지 관리할 수 있다.

그렇다면 하나의 테이블스페이스는 256개 익스텐트를 넘길 수 없나?

물론 그럴 리 없다. FSP_HDR의 용량을 초과하는 경우, InnoDB는 자동으로 XDES 전용 페이지(XDES Page)를 추가한다.

XDES Page

XDES Page는 FSP_HDR 페이지의 확장 역할을 수행한다.
FSP_HDR 페이지와 기본 구조는 동일하지만, 상단의 FSP Header 영역은 대부분 0으로 채워진다.
(FSP_HDR 페이지) - (FSP Header) 라고 생각하면 된다.

테이블스페이스가 256MB 이상 커질 경우 256MB마다 하나의 XDES 페이지가 추가된다고 이해하면 된다.

INODE Page

INODE Page는 세그먼트가 어떤 익스텐트들이 소유하고 있는지, 어떤 상태인지 등을 추적하는 역할을 한다.
앞서 FSEG 상태의 인스텐트들은 여기서 관리된다.

기본적으로 INODE Page는 페이지 번호 2번에 존재하며, 하나의 페이지당 최대 85개의 INODE Entry를 포함할 수 있다.
각 Entry는 하나의 세그먼트를 의미하며, 해당 세그먼트가 관리 중인 익스텐트 리스트와 조각 페이지들을 추적한다.

INODE Entry 구조

필드설명
Segment ID해당 세그먼트의 고유 식별자
NOT_FULL 사용 페이지 수현재 NOT_FULL 익스텐트에서 사용 중인 페이지 수
리스트 포인터들FREE, NOT_FULL, FULL 리스트의 이중 연결 리스트 base node
Fragment Array최대 32개의 조각 단위로 할당된 페이지 정보

Fragment Array

앞서 말했듯이, 세그먼트는 처음 생성되었을 때 익스텐트를 한 번에 할당받지 않는다.
대신 최대 32개의 페이지를 조각(fragment) 단위로 받아서 쓴다.
이게 바로 Fragment Array에 저장된다.

이후 공간이 더 필요해지면 InnoDB는 익스텐트를 통째로 할당하게 되고, 그때부터는 조각 대신 익스텐트 기반으로 동작한다.

상태 리스트 (FREE, NOT_FULL, FULL)

각 세그먼트는 자신이 소유한 익스텐트들을 상태에 따라 리스트로 관리한다.

  • FREE: 완전히 비어있는 익스텐트들
  • NOT_FULL: 일부 페이지만 사용 중인 익스텐트들
  • FULL: 모든 페이지가 사용 중인 익스텐트들

익스텐트 상태가 바뀌면 이 리스트 간에 이동이 발생한다.
예를 들어 어떤 익스텐트가 가득 차면 NOT_FULL -> FULL, 다시 공간이 생기면 FULL -> NOT_FULL로 옮겨진다.
완전히 비게 되면 FREE로도 이동할 수 있다.

이 구조 덕분에 InnoDB는 각 세그먼트 단위로 공간을 세밀하게 관리하고, 빠르게 할당 여부를 판단할 수 있다.

추가 페이지

하나의 INODE 페이지는 85개의 세그먼트(INODE Entry)만 관리할 수 있다.
XDES Page와 동일한 원리로 85개의 세그먼트를 초과하면 추가 INODE Page가 생긴다.

정리

지금까지 내용을 요약해보자.
InnoDB는 파일 전체를 관리하는 메타데이터 구조를 여러 페이지에 걸쳐 계층적으로 유지한다.

  • FSP_HDR Page는 테이블스페이스 전체의 출발점으로, 공간 확장과 할당 전략의 기준이 되는 정보를 담는다.
  • XDES Entry는 각 익스텐트의 상태와 페이지 사용 현황을 관리한다.
  • INODE Page는 세그먼트가 자신이 소유한 익스텐트를 상태별로 추적할 수 있게 한다.

InnoDB의 메타데이터 구조는 처음 보면 꽤 복잡해 보이지만, 한 번 전체 흐름을 잡고 나면 오히려 예측 가능하고 합리적인 구조였다.

아래는 내가 JCole의 블로그 자료를 바탕으로 전체 구조를 한눈에 볼수 있게 만든 도식이다.

profile
나는 개발자다. 5000만큼 코딩한다.

0개의 댓글