1. Storage
우리가 생각하는 저장장치는 크게 2개로 분류 된다.
- Volatile Device : 휘발성 저장장치
- 전력이 사라지면 데이터를 잃는다.
- byte-addressable하기 때문에 조금 더 빠르게 접근 할 수 있다.
- Non-Volatile Device : 비 휘발성 저장장치
- 전력이 사라져도 데이터를 잃지 않는다.
- Block과 Page를 통해서 접근가능하다 (4KB) 정도 된다.
강의에서는 “Persistent memory”라는 걸 설명하는데 필요하다면 논문을 참조 하라고 한다. 이는 DRAM보다 빠르지만 disk처럼 전력이 사라져도 데이터를 잃지 않는다.
- 저장장치에 서 중요한 것은 DBMS의 역할이다. 결국 DBMS는 Disk에서 데이터를 가져와서 Memory에 올려 놓는 즉 “Volatile Device와 Non-Volatile Device”간의 데이터를 어떻게 효율적이면서 안전하게 통제하는가를 중요한 문제로 삼고 있다. 여기에서 주목해야하는 점은 Disk로부터 Memory 사이의 데이터 교환의 latency(지연)을 줄이는 것을 목표로 해야한다.
2. Disk-Oriented DBMS Overview
Database라 함은 모두 disk에 존재하고 disk에 file로 file안에 page로 page안에 block으로 나누어서 저장되어 있다. DBMS의 역할은 이러한 Block 혹은 Page의 데이터를 Memory로 옮겨오는 것이다.
용어
- Buffer pool: Buffer pool은 disk와 memory사이에서 데이터를 교환해 주는 역할을 한다.
- Execution engine : Execution engine은 client의 query를 수행한다.
결국 DBMS는 Execuction engine이 buffer pool에게 특정 page를 요청하고 buffer pool은 이를 메모리로 가져온 뒤 Execution engine이 이후 요청을 처리하는 것이 기본이 된다.
전체 흐름도
client -> Execution engin -> buffer pool
|
Memory <-> Disk
|
client -> Execution engin <- buffer pool
3. DBMS vs OS
이부분이 제일 잘 이해가 되지 않는다. 강의의 요점은 OS를 믿을 수 없기 때문에 DBMS를 사용한다는 것이다. 우선 OS의 기억을 살려서 Virtual Memory에 대해서 알아보자
Virtual Memory
조금 원시의 시대로 돌아가서 Memory가 64MB와 같이 극한의 리소스를 가지고 있다고 가정을 해보자. 우리가 쓰는 프로그램이 1GB라고 생각을 하면 우선 모든 코드가 Memory에 올라갈 수 없다는 생각을 하게 된다.
이때 우리가 Virtual Memory를 사용하게 되는데 원리는 간단하다.
모든 데이터를 메모리에 올리는 것이 아니라 필요한 Page만 Memory에 올리면 된다는 것이다. 이를 통해 아래와 같은 구성의 다이어그램을 그릴 수 있다.
CPU <-> Virtual Memory <-> Physical Memory <-> Disk
(그림 추후 첨부)
(VM : Virtual Memory) 결과적으로 VM을 사용하게 되면서 더 사용자는 조금 느리지만 많은 페이지를 가져올 수 있게 되는 것이다.
글에서 DBMS의 목표는 VM을 적절하게 사용함으로서 disk에 접근하는 횟수를 줄이고 disk에 접근해서 데이터를 fetching하는 동안 다른 query를 진행하게 하는 것을 그 목적으로 한다.
이러한 목적을 이루게 해주는 자료구조?가 “mmap” 을 통해서 구현되어있다. 아래 page에서 mmap에 대한 discription을 볼 수 있는데 실제로 c에서는 mmap을 통해서 addr를 넣고 길이만큼의 virtual address를 얻을 수 있게 되어있다. (필자는 현재 써보지 않았다.)
https://man7.org/linux/man-pages/man2/mmap.2.html
이런 mmap을 이용한 virtual memory가 모든걸 해결해 줄꺼 같지만 사실 OS를 배워본 사람이라면 문제를 알고 있을 것이다. Page Fault 가 나는 경우에 교체하는 알고리즘에 따라 차이가 있긴 하겠지만 결국 disk에서 데이터를 읽어 들여와야 하기 때문에 Bottle Neck이 되는 것을 막을 수 없다.
OS가 많은 함수로 도움을 주긴 하지만 결과적은 OS는 우리의 친구가 될 수 없다고 이야기한다. 해서 우리는 더 정확하고 효율적으로 데이터를 사용하기 위해서 DBMS를 사용해야한다.
4. File Storage
이러한 DB를 구성하는 file에는 크게 3개의 layer가 존재한다.
- File Storage Layer -> 우리가 보는 file들의 layer
- Page Layout -> file을 실제로 disk에 저장하는 단위
- Tuple Layout -> page내부에 실제로 존재하는 데이터들의 집합
OS는 각 file이 어디에 있는지를 알 수 없기 때문에 DBMS를 통해서 file을 찾고 읽을 수 있어야 한다.
5. Database Page
지속적으로 설명하는 것 처럼 Database는 file들을 저장하는데 이는 고정된 크기의 block을 가지는 page 로 구성이 되어있다. 또한 이 page에는 한 page에 필요한 모든 정보가 들어 있음을 기본으로 한다. (self-contained)
Page는 각 페이지 마다 Unique identifier를 가지고 있으며 대부분은 DBMS는 간적적으로 page id를 가지는 path와 offset을 가진다. 결국 특정 주소에서 떨어진 값을 타고 들어가 데이터를 읽는 방식이다.
이런 Page는 각 개념마다 조금 다르게 크기를 가진다.
- Hardware page : 4KB
- OS page : 4KB라고 써져 있지만 x64운영체제에서는 2MB ~ 1GB까지 간다.
- Database page : 1-16KB이고 각 DBMS마다 구현에 따라 다르다.
중요한 원칙은 해당 Page는 절대 이 크기를 넘어선 데이터를 쓰지 않는다. (쓸 수도 없을 것이다.) DBMS에서는 요청은 “쓰거나 쓰지 않거나” 둘중에 하나 만을 선택해서 진행한다.
강의에서 나온 질문 Q : Page size가 크면 Disk에 쓰는게 오래걸리지 않냐? A : 결국 이런 상황에서 최적의 크기와 알고리즘을 찾는 것이 Engineer가 해야할 목표이다.
6. Database Heap
여기서 말하는 Heap은 우리가 자료구조에서 아는 Heap과는 조금 다르다. DBMS는 page_id를 LinkedList 혹은 page directory를 통해서 disk에 저장한다.
- LinkedList는 header page가 각 page의 free page와 data page를 pointing하고 있는데 이는 새로운 요청이 들어올 때마가 각 페이지를 full scan해야하는 번거로움이 존재한다.
- page directory는 special page를 통해서 각 page의 free space를 추적할 수 있다???
7. Page Layout
이부분은 이전에 작성해 놓은 slotted Page를 참고하면 도움이 된다.
8. Tuple Layout
Tuple은 Page에 저장되는 byte데이터가 된다.
각 Tuple은 아래와 같은 구조를 가지게 된다.
- Tuple Header : 각 Tuple의 Meta data를 저장해 놓는다.
- 동시성을 제어할 수 있는 concurrency control protocol
- Bit Map for NULL values
- Tuple Data : 각 데이터
- Unique Identifier: 고유한 식별자
- 이 부분이 강의에서 봤던 좀 신기한 부분인데 각 튜플은 특정한 identifier를 가진다.
- 보통 page_id + offset or slot을 통해서 표기한다. (추후 이미지 첨부 예정)