콘텐츠로 이동

데이터베이스 1편 - 메모리와 디스크가 만드는 영속성의 비용 구조

Published: May 19, 2026

Redis 엔지니어링 팀은 보고서에서 한 가지 명확한 패턴을 짚었다. “성능은 서서히 저하되지 않는다.” 실제로 대규모 벡터 데이터를 다루던 한 개발 팀은 데이터 규모가 RAM 용량을 초과하는 순간, 쿼리 속도가 급격히 떨어지는 현상을 겪었다.

동일한 현상이 2015년 디스코드(Discord)의 몽고DB(MongoDB) 운영 과정에서도 나타났다. 데이터와 인덱스의 총량이 RAM 크기를 넘어선 순간, 안정적이던 시스템의 메시지 로딩 속도가 순식간에 한계에 직면했다.

Reference: Vector DB / Redis
Reference: Discord



데이터 타입과 시간대는 다르지만 두 팀이 직면한 본질은 같다. 데이터가 메모리를 떠나는 순간, 시스템은 천 배의 비용을 지불해야 하는 디스크에서 자원을 조달하기 시작한다. 데이터베이스 성능의 운영방식은 결국 효율적인 자원 배치 문제로 귀결된다.

데이터가 어디에 위치하느냐가 시스템의 생산성을 결정한다.


데이터베이스의 최우선 가치는 **영속성(Persistence)**이다. 전원이 꺼지거나 예기치 못한 리스크가 발생해도, 데이터는 안전하게 보존되어야 한다.

이 약속은 역설적으로 데이터베이스를 전체 아키텍처에서 비용이 가장 높은 매체인 디스크에 묶어버리는 원인이 된다. 각 저장 매체의 접근 속도와 비용의 차이는 선형적이지 않다.

L1 캐시 ~1 ns
RAM ~100 ns (L1보다 100배 느림)
SSD ~100,000 ns (RAM보다 1,000배 느림)
HDD ~10,000,000 ns (RAM보다 100,000배 느림)

**내부 자원인 RAM(메모리)**에서 데이터를 꺼내오는 것과 **외부 시장인 SSD(디스크)**에서 조달하는 것은 단위 자체가 다른 지출이다. 데이터가 메모리를 벗어나면 초당 처리할 수 있는 거래의 양이 급격히 제한되기 때문이다.

여기서 데이터베이스의 근본적인 트레이드오프가 발생한다. 안전한 보존을 위해 디스크에 기록하는 ‘데이터 보존’ 비용과, 즉각적인 서비스 제공을 위해 작업을 메모리에서 완결하려는 ‘운영 효율성’ 사이의 팽팽한 균형 잡기다.

그러므로 시스템 지연이라는 비용이 발생했을 때 엔지니어가 던져야 할 첫 번째 질문은 인덱스의 부재가 아니다. 해당 데이터가 자체 유동성(메모리) 범위 내에 머물고 있는지, 아니면 비싼 외부(디스크 I/O)에 의존하고 있는지를 판별하는 것이다. 이 자본 효율적인 판단이 디버깅 방향을 가른다.


디스크 접근을 줄이려면 데이터를 메모리에 머물게 해야 한다. 데이터베이스가 이를 위해 RAM에 확보한 전용 공간이 바로 **버퍼 풀(Buffer Pool)**이다.

이곳은 단순한 ‘임시 캐시’가 아니다. 데이터베이스에서 메모리는 자산을 쌓아두는 창고가 아니라, 모든 가치 창출이 발생하는 메인 작업장이기 때문이다.

디스크와 메모리는 철저한 분업 구조로 움직인다. 두 매체가 정의하는 ‘읽기와 쓰기’의 개념은 본질적으로 다르다.

  • 디스크의 거래(I/O): 자산 내용을 수정할 수 없는 단순한 **‘이송 및 보관’**이다. 디스크는 스스로 고부가가치 연산을 수행하지 못한다.
  • 메모리의 거래(Buffer Pool): CPU가 직접 접근하여 자산 가치를 바꾸는 **‘실질적인 가공 및 정산’**이다.

하드웨어적 제약 때문에 모든 비즈니스 연산은 디스크에서 페이지를 버퍼 풀로 들여온 뒤에만 시작된다.

  • 자산 조회(Read) 시: 디스크에서 페이지를 통째로 버퍼 풀에 복사한다. 시스템은 이 공간 내부를 뒤져 데이터를 선별한다. 디스크가 스스로 내용물을 분류해 주지 않기 때문이다.
  • 자산 수정(Update) 시: 디스크 수치를 직접 고치지 않는다. 버퍼 풀의 페이지를 열어 내용을 먼저 수정한다. 수정된 페이지(Dirty Page)들은 버퍼 풀에 머물다가 나중에 디스크로 이송되어 덮어쓰기 방식으로 기록된다.

결국 디스크는 물리적 조달만 담당하며, 가치를 더하는 실질적인 자본 운용은 오직 메모리 위에서만 발생한다.

워킹셋과 작업장 면적의 경제적 한계

섹션 제목: “워킹셋과 작업장 면적의 경제적 한계”

시스템의 성패는 워킹셋(현재 활발히 거래되는 데이터 규모)이 확보된 작업장 용량 안에 모두 수용되느냐에 달려 있다.

메모리는 고비용 희소 자원이다. 한정된 설비가 워킹셋을 감당하지 못하는 순간, 자원 운용 효율은 급격히 악화된다.

  • 교체 및 재조달 비용: 새 데이터를 들여오려면 기존 페이지를 내보내야 한다. 이때 발생하는 재조달 비용(Disk I/O)은 생산성을 갉아먹는다. 특정 자원을 유지하는 선택은 밀려난 다른 자원의 재조달 기회비용을 지불하겠다는 뜻이다.
  • 점진적 저하가 아닌 ‘임계점’ 도달: 부족한 용량 탓에 내보냈던 데이터를 즉시 다시 가져오는 상황이 반복되면, 시스템은 완만한 저하가 아닌 급격한 처리량 하락을 겪는다.

디스코드와 벡터 DB 팀의 장애는 보유한 설비 용량이 감당할 수 있는 거래의 임계치를 넘어서며 발생한 자원 고갈 현상이었다. 성능 한계는 제한된 설비가 작업량을 견디지 못할 때 나타나는 필연적 결과다.


OS도 파일을 읽을 때 **페이지 캐시(Page Cache)**를 활용한다. 디스크 데이터를 RAM에 상주시키는 목적은 버퍼 풀과 같다. 그럼에도 DB가 자체 작업 공간을 구축하는 이유는 무엇일까?

범용 관리자인 OS에게 메모리 제어권을 맡기기에는 데이터베이스 작업의 특수성과 비용 구조가 전혀 다르기 때문이다.

데이터베이스의 자체 데이터 식별을 통한 우선순위 결정

섹션 제목: “데이터베이스의 자체 데이터 식별을 통한 우선순위 결정”

OS는 모든 프로세스를 공평하게 관리한다. 자산의 개별 가치를 식별할 수 없는 OS는 단순히 최근에 접근되지 않았다는 사후적 통계만으로 핵심 자산(인덱스 페이지)을 메모리 밖으로 내쫓는 자원 배분 오류를 범한다.

[ OS ]
"모든 프로세스를 공평하게 관리"
Chrome VSCode DBMS Game Python
│ │ │ │ │
└─────────────┴─────────────┼──────────────┴──────────────┘
동일한 기준으로 메모리 관리
[ Page A ] [ Page B ] [ Page C ] [ Page D ]
"누가 더 중요한지 모름"

반면 데이터베이스는 자산의 가치를 정확히 식별한다. 어떤 데이터가 수천 번의 쿼리를 돕는 핵심 자산인지 구분하여, 활용도가 높은 페이지를 버퍼 풀에 집요하게 유지한다.

[DBMS]
"나는 어떤 페이지가 중요한지 이미 알고 있다"
SELECT * FROM orders WHERE user_id = 10;
Query Plan
└──→ [ Index Page ] ──→ [ Leaf Page ] ──→ [ Data Page ]
↑ ↑ ↑
반복 접근 예상 다음 접근 경로 예측 실제 데이터
(Hot)
Cache Priority
[ Index Page ] >>> [ Leaf Page ] >>> [ Cold Data Page ]
곧 다시 읽힐 페이지"를 예측해서 오래 유지

쿼리 실행 계획에 근거한 자원 투자

섹션 제목: “쿼리 실행 계획에 근거한 자원 투자”

OS의 캐싱 전략은 전적으로 과거의 기록에 의존한다. 방금 읽었으니 다시 읽을 가능성이 높다는 추측에 기반하기 때문이다.

[OS : LRU(Least Recently Used)]
Page Access
A ─→ B ─→ C ─→ D ─→ B ─→ C ─→ E
Recently Used
HOT ──→ [ C ] [ B ] [ D ] [ E ] ──→ COLD
Remove [ A ]

반면 데이터베이스는 쿼리 실행 계획을 통해 다음에 필요한 데이터를 미리 파악하고 있다. 특정 자원 취득 시 뒤이어 발생할 수요를 알고 디스크에서 미리 선행 매입(Preload)한다. OS의 사후 추정보다 훨씬 효율적이다.

[DBMS : Predict]
SELECT * FROM orders WHERE user_id = 10;
Query Plan
[Index Page] ──→ [Leaf Page] ──→ [Data Page]
│ │ │
└────────────────┼────────────────┘
Next Page Prediction
SSD ──→ Buffer Pool Preload

이중 버퍼링 우회를 통한 독점적 효율성

섹션 제목: “이중 버퍼링 우회를 통한 독점적 효율성”

데이터베이스가 OS 캐시에 의존하면 동일한 데이터가 OS 영역과 DB 영역에 중복 적재되는 이중 버퍼링이 발생한다. 이는 한정된 자본(RAM)의 비효율적인 중복 지출이다.

[ Double Buffering ]
┌───────────┐ ┌───────────────┐ ┌────────────────┐ ┌───────┐
| SSD / HDD | ─→ | OS Page Cache | ─→ | DB Buffer Pool | ─→ | Query |
└───────────┘ └───────────────┘ └────────────────┘ └───────┘
Copy #1 Copy #2

고성능 데이터베이스는 O_DIRECT 플래그라고 불리는 직접 접근 메커니즘을 통해 OS 캐시를 우회하고 하드웨어와 직접 통신한다. 이러한 직거래 구조를 통해 중복 지출을 제거하고 확보된 자원을 자체적 비즈니스 쿼리에 따라 배분한다.

[ O_DIRECT ]
┌───────────┐ ┌────────────────┐ ┌───────┐
| SSD / HDD | ─────────────────→ | DB Buffer Pool | ──→ | Query |
└───────────┘ └────────────────┘ └───────┘
OS Cache Bypass

결국 OS는 훌륭한 범용 관리자이지만, 데이터베이스 내부에서 이루어지는 특수한 상황까지 알지는 못한다. 데이터베이스만을 위한 작업장이 할당된 것은 가장 효율적인 결정을 내기 위한 합리적인 선택이다.


캐시 페이지 뒤에 숨은 기회비용

섹션 제목: “캐시 페이지 뒤에 숨은 기회비용”

버퍼 풀의 운용 공간은 유한하다. 새 페이지를 들여오는 결정은 기존 자산을 포기를 동반한다.

경제학자 제임스 뷰캐넌은 기회비용을 ‘선택한 대상의 가격’이 아니라 포기해야 했던 대안 중 가장 가치 있는 것로 정의했다. 버퍼 풀의 자산 배분 역시 이 원칙을 따른다. 특정 페이지 A를 메모리에 유지하는 진짜 비용은 16KB라는 물리적 용량이 아니다. A를 보유하기 위해 포기한 대안, 즉 **A 때문에 밀려난 B를 디스크에서 다시 가져올 때 치러야 하는 성능 손실(비용)**이 진짜 대가다.

Reference: Library of Economics and Liberty: Opportunity Cost

이 관점에서 LRU(Least Recently Used)는 자산 관리의 핵심 의사결정 모델이다. “최근 거래가 없었던 자산이 미래 가치도 가장 낮을 것”이라는 가정을 바탕으로, 포기했을 때 손실이 가장 적은 대상을 골라내는 영리한 자산 매각 알고리즘이기 때문이다.

사용 빈도를 기준으로 미래 가치를 추정하는 LFU(Least Frequently Used)나, 일시적인 대량 매입이 우량 자산 포트폴리오를 오염시키지 않도록 방어하는 InnoDB의 LRU 변형 구조도 본질은 같다.

이름은 제각각이지만 모두 같은 질문에 답하고 있다. 이 한정된 워킹셋을, 어떤 데이터에 내줄 것인가.


메모리 한계 초과 시 세 가지 대응 전략

섹션 제목: “메모리 한계 초과 시 세 가지 대응 전략”

쿼리 성능 저하 시 가장 먼저 확인할 지표는 **버퍼 풀 히트율(Buffer Pool Hit Ratio)**이다. 이 수치가 떨어진다는 것은 메모리가 워킹셋을 감당하지 못해 디스크 접근이 빈번해지고 있다는 신호다. 이때 엔지니어는 자본 배분을 재조정해야 한다.

데이터 점유 제거를 통한 워킹셋 축소

섹션 제목: “데이터 점유 제거를 통한 워킹셋 축소”

메모리를 점유할 가치가 낮은 데이터를 정리하는 전략이다. 사용하지 않는 인덱스를 삭제하거나 오래된 데이터를 아카이빙하면, 핵심 데이터가 메모리에서 밀려나는 상황을 대비할 수 있다. 현재 선택으로 인해 발생하는 기회비용을 물리적으로 제거하는 근본적인 방법이다.

설계를 변경할 여유가 없을 때 가장 명확한 선택이다. RAM 용량을 늘려 작업장 자체를 확장하면, 자원을 두고 벌이는 경합 구조 자체가 해소된다. 개발을 통한 최적화 비용보다 하드웨어 비용이 저렴할 때 선택하는 자본 효율적 전략이다.

디스크 중심 아키텍처로의 전환

섹션 제목: “디스크 중심 아키텍처로의 전환”

데이터 규모가 너무 커서 메모리 증설만으로 감당이 안 된다면, 메모리 상주를 포기해야 한다. 이때는 디스크 읽기를 ‘실패’가 아닌 ‘당연한 비용’으로 계산하는 시스템(LSM 트리 등)으로 이주한다. 비싼 메모리 영토를 지키기 위해 분투하는 것보다, 저렴한 디스크를 효율적으로 활용하는 것이 장기적으로 더 이득이기 때문이다.


데이터베이스는 영속성을 보장하는 대가로 가장 느린 매체인 디스크를 안고 간다. 이 태생적 한계를 극복하는 유일한 방법은 디스크 읽기를 최소화하는 것뿐이며, 버퍼 풀은 그 전략이 실행되는 실제 작업장이다. 작업장의 모든 페이지 점유는 곧 기회비용의 결정이다.

따라서 엔지니어에게는 두 가지 선택지가 있다. 돈으로 RAM을 사서 시간을 버는 것, 그리고 구조적 최적화로 디스크 접근을 줄여 시간을 만드는 것이다. 핵심은 비용의 지불 방식을 정확히 인지하는 데 있다. 구조를 이해한 엔지니어는 시스템 지연 앞에서 당황하지 않고 그 한 가지 질문을 던진다.

현재 워킹셋이 작업장에 수용되고 있는가? 그렇지 않다면, 어떤 기회비용을 감수할 것인가?

다음 편: 워킹셋이 작업장에 담기지 않을 때, 애초에 디스크 접근 횟수 자체를 물리적으로 줄이는 방법을 다룬다. 매 쿼리마다 테이블의 99%를 건너뛰는 기술, 바로 인덱스다.