GFS에는 아래와 같은 문장이 나온다.
The checkpoint is in a compact B-tree like form that can be directly mapped into memory and used for namespace lookup without ex-tra parsing. This further speeds up recovery and improves availability.
전체적인 느낌은 이해가 되었지만 directly mapped into memory
라는 내용이 어떻게 동작하는지 잘 이해되지 않았다. 그래서 이번 글은 MemoryMapedFile에 대한 내용을 정리해본다.
What is checkpoint in GFS
GFS에서 Master는 3가지 Metadata를 저장한다.
- the file and chunk namespaces
- the mapping from files to chunks
- the locations of each chunk’s replicas
처음 두 가지의 메타 정보는 operation log
를 사용해서 disk에 저장이 되는 것을 보장하게 된다. GFS의 2.6.3 Operation Log
에서는 여러개의 Operation Log를 주기적으로 checkpoint로 merge해서 저장한다는 내용이 나온다. 장애가 발생한 상황에서 가장 마지막 checkpoint + 아직 checkpoint로 저장되지 않은 Operation Log만 빠르게 로딩해서 recovery를 빠르게 하고 availability를 개선한다는 내용이다.
The checkpoint is in a compact B-tree like form that can be directly mapped into memory and used for namespace lookup without ex-tra parsing. This further speeds up recovery and improves availability.
MemoryMappedFile이 무엇이길래 recovery가 빨라지고 availability가 개선된다는걸까? 이 부분을 이해하기 위해 우선 CS 개념을 다시 리마인드해보았다.
CPU, Memory, Disk의 동작 과정
기초 개념부터 다시 훑어봤지만 여기서는 간단하게 정리해보려고 한다.
- CPU - Register - L1/L2/L3 Cache - Memory - Disk 순서대로 데이터가 접근된다
- Memory는 Logical Memory, Physical Memory로 구분된다
- CPU가 처리하는
연산자 + 데이터
는 16 bit이다. - Memory의 주소 공간은 1 Byte 단위이고,
연산자 + 데이터
는 2개의 메모리 주소 공간에 나누어서 저장된다. - 32 Bit CPU에서는 최대 4GB의 메모리를 사용할 수 이었고, 64 Bit CPU는 64개 bit로 구성된 주소를 처리할 수 있게 되었다.
- Memory는 Logical Address Physical Address로 나뉘어진다.
- Process는 각자 독립적인 Logical Address를 가지고 Access할 때 Physical Address로 변환되어서 사용된다.
- Page는 Virtual Memory를 고정 크기로 나눈 것이고 Frame은 Physical Memory를 구정 크기로 나눈 것이다.
- 메모리에서 Page, Frame은 동일한 사이즈를 가지고, Disk에서도 메모리에 로딩하기 위해 동일한 크기만큼 Page가 로딩된다.
- Memory와 Disk 사이에는 Page Cache가 존재한다. 불필요한 Disk IO를 OS 레벨에서 제어하는 역할을 한다.
- Page Cache가 점유하고 있는 메모리 크기는
free -h
로 확인 가능하다.
Read, Write의 동작 과정
Application에서 일반적인 File I/O를 하는 과정에서는 2가지 Buffer가 사용된다. Application Level에서 선언한 Byte Buffer (User Buffer), Page Cache라고 불리는 Kernel Buffer이다. 일반적인 Write에서는 Application User Buffer -> Kernel Buffer 로의 copy가 1번 일어나고, Kernerl Buffer에서 Disk로 write-back하면서 한 번 더 copy가 일어난다. Read에서도 Disk -> Kernel Buffer -> User Buffer로 copy가 2번 일어난다. (Disk에서 Kernel Buffer로의 이동도 Hardware에서 Kernel Buffer로의 이동이기 때문에 copy의 종류라고 생각했다.)
MemoryMappedFile에서는 UserBuffer를 사용하지 않는다. Application에서 MemoryMappedFile을 선언하면 Virual Memory 영역에 Disk에 저장된 File에 대한 참조가 생성된다. 그리고 처음으로 접근할 떄 Page Fault가 발생하고 Disk -> Kernel Buffer로의 Page 이동이 일어난다. 그리고 그 이후에는 OS의 Page 정책에 따라서 File의 필요한 부분만 Kernel Buffe로 로딩된다.
Memory Mapped I/O를 사용하는 이유
- UserBuffer를 사용하지 않기 떄문에 COPY가 1번이라서 I/O가 더 빠르다.
- GFS에서는
without ex-tra parsing
라고 표현했는데, Application Memory에서 객체로 관리하기 위한 Binary -> Object로의 변환 과정도 없이 바로 필요한 값에 접근할 수 있다. 이렇게 binary에서 필요한 값을 바로 찾기 위해서는 byte 단위로 데이터가 어떻게 저장되어 있는지를 다루는 specification이 내부적으로 정의되어 있을듯하다. - File 사이즈가 1GB라도 OS의 Page 전략에 따라 File 전체가 Kernel Buffer에 로딩되지 않고도 사용될 수 있다. Application에서 RandomAccess나 Stream을 통해서 File 전체를 User Buffer에 로딩하지 않고 사용할 수 있다면, Kernel Buffer에서는 Paging을 사용해서 File에서 필요한 부분만 로딩해서 사용한다.
Native Memory vs Direct Memory
JVM 기준으로 생각해보면 MemoryMappedFile은 Heap을 사용하지 않는다. Native memory라고도 하고 Off-heap이라고도 한다. 중요한 점은 GC의 영향 범위를 벗어난 영역이라는 점이다. Direct Memory는 Native Memory랑 동일하게 Heap을 사용하지 않는다. Direct Memory는 Disk와 같은 H/W와의 상호작용을 암시하는 의미를 가진다. JVM에서 Heap 밖의 영역을 사용할 때 Application에서 직접 메모리 관리를 컨트롤하기 위한 목적으로 사용한다면 Native Memory를 사용한다고 할 수 있다. 반면 SSD, Network와 같이 하트웨어 장비에 mapping해서 사용하기 위한 목적이라면 똑같이 Off-Heap을 사용하지만 Direct Memory를 사용한다고 표현하는 것이 더 적합하다.
Reference
https://www.youtube.com/watch?v=K9L9YZhEjC0
'DEV > System Design' 카테고리의 다른 글
안정 해시 Consistent Hash (0) | 2025.05.04 |
---|---|
처리율 제한 장치, Rate Limiter (0) | 2025.05.04 |
Google File System 리뷰 (1) | 2025.04.20 |
개략적인 규모 추정 :: 숫자에 대한 감 잡기 (0) | 2025.04.12 |
CAP Theorem in Google File System (0) | 2025.04.12 |