0. 들어가며


OS에는 이미 파일 시스템이 있다. OS는 파일을 읽고 쓸 수 있고, 메모리를 관리할 수 있고, page cache로 파일 데이터도 캐시해준다. 그런데 DBMS는 굳이 자기만의 buffer pool을 만들고, WAL을 관리한다. fsync() 타이밍을 신경 쓰고, 어떤 경우에는 Direct I/O까지 사용한다.

OS가 이미 다 해주는 것 같은데, DBMS는 왜 굳이 직접 하려고 할까? 이 글은 이 질문에서 출발했다.

결론부터 말하면, OS가 부족해서가 아니다. OS는 범용 시스템으로서 매우 강력하다.

다만 OS는 데이터베이스 안의 데이터가 어떤 의미를 가지는지는 모른다. OS에게는 어떤 파일의 특정 offset에 있는 page일 뿐이다. 하지만 DBMS에게는 전혀 다른 의미를 가진다. 그것은 WAL일 수도 있고, index page일 수도 있고, dirty data page일 수도 있다. 때로는 곧 checkpoint 대상이 될 page이거나, 한 번만 읽고 버릴 scan page일 수도 있다.

I/O 관점에서 DBMS는 일반 애플리케이션과는 다른 성격을 가졌기 때문에 메모리 관리와 디스크 I/O를 세밀하게 제어할 필요가 있다. 이를 이해하기 위해서는 다양한 지식을 알아야 하는데 관련 내용을 한번 이 글에서 알아보자.

1. DBMS는 왜 OS가 아쉬운가


DBMS가 OS에게 모든 I/O를 맡기기 어려운 이유는 단순히 OS가 느려서가 아니다.

DBMS는 transaction, durability, recovery, tail latency 등을 중요하게 생각해야하는 애플리케이션이다. 따라서 DBMS를 만들때는 아래 질문들에 대한 결정을 하며 구현해나가야한다.

  1. 데이터를 읽고 쓸때, 어떤 데이터를 메모리에 남기고, 어떤 것을 디스크로 밀어낼 것인가?
  2. 어떻게 해야 장애가 나도 복구할 수 있을 만큼 안전하게 기록되는가?
  3. 데이터를 어떻게 디스크에서 읽어올 것인가?

대부분 일반 애플리케이션의 경우 위와 같은 고민을 하지 않고 OS에게 자원 관리를 전적으로 맡기지만, OS는 범용적인 케이스에 탁월할 뿐 DBMS 같은 뾰족한 요구사항이 있는 경우 메모리/디스크 관리에 대한 제어권을 전부 줬을 때 아쉬운 상황이 생긴다.

예를 들어 write() 호출을 성공했다는 말은 대체로 “커널이 데이터를 받았다” 라는 의미를 가진다. 하지만 DBMS에서는 그게 부족하다. 장애가 나도 디스크를 통해 복구를 하려하는 DBMS의 입장에서는 write() 만 믿다간 아직 디스크에 반영되지 않은 경우가 있기 때문이다.

또한 DBMS 입장에서는 자주 접근하는 데이터라 메모리에 계속 올려두고싶거나, 일회성 큰 scan으로 메모리에서 내리고 싶은 데이터가 있을 수 있다. OS 입장에서는 이를 알 수 없다. 그리고 이는 곧 DB의 성능 저하로 이어진다.

2. 파일 I/O를 OS에게 맡긴다는 것은 무슨 뜻인가