---
title: "Databricks가 Postgres 데이터를 S3의 Parquet로 저장해 트랜잭션과 분석을 합치려는 방식"
published: 2026-07-01T12:48:56.000Z
canonical: https://jeff.news/article/4685
---
# Databricks가 Postgres 데이터를 S3의 Parquet로 저장해 트랜잭션과 분석을 합치려는 방식

Databricks가 Lakebase와 LTAP 아키텍처를 설명하며, Postgres의 WAL과 데이터 파일을 외부 서비스로 분리하고 운영 데이터는 Parquet 기반 오픈 포맷으로 저장하는 접근을 소개했음. 목표는 CDC나 미러링 없이 하나의 데이터 사본으로 트랜잭션과 분석을 동시에 처리하는 것임.

## Databricks가 말하는 문제의 출발점은 “전통 DB는 한 박스에 너무 많은 걸 넣었다”임

- Reynold Xin은 Berkeley 박사과정 시절 “OLTP 데이터베이스는 이미 해결된 문제”라는 조언을 들었다고 함
  - 그래서 Apache Spark가 된 연구 프로젝트와 Databricks로 이어지는 분석 쪽에 집중했음
  - 그런데 실제로 Databricks를 만들며 여러 데이터베이스를 써보니 OLTP는 여전히 투박하고, 확장하기 어렵고, 장애에 취약했다고 봄
  - 그 질문에서 나온 게 serverless Postgres 데이터베이스인 Lakebase임

- 전통적인 Postgres, MySQL, Oracle 같은 DB는 대체로 모놀리식 구조임
  - 한 머신에 데이터베이스 엔진과 저장소가 같이 있고, 디스크에는 크게 WAL과 data files가 있음
  - 커밋할 때 데이터 파일을 바로 랜덤 I/O로 고치는 대신, 변경 내용을 WAL에 순차 append하고 나중에 비동기로 데이터 파일을 갱신함
  - 쉽게 말해 WAL은 쓰기를 빠르고 안전하게 만들고, data files는 읽기를 빠르게 만듦

- 문제는 WAL과 data files가 한 머신 안에 묶여 있다는 데서 계속 나옴
  - 디스크 flush 설정이 잘못되면 클라이언트에는 커밋됐다고 했는데 정전이나 kernel panic 때 사라질 수 있음
  - 머신 디스크가 죽으면 WAL과 데이터 파일도 같이 위험해짐
  - read replica나 HA standby를 만들려면 전체 DB의 물리 복사본을 만들어야 해서 느리고 비쌈
  - 무거운 분석 쿼리는 트랜잭션 트래픽과 같은 CPU·메모리·스토리지를 놓고 싸움

## Lakebase는 Postgres compute를 stateless하게 만들려고 WAL과 page를 뜯어냄

- 핵심 아이디어는 현대 클라우드의 기본 재료를 쓰자는 것임
  - cheap하고 durable한 object storage, elastic compute를 전제로 OLTP를 다시 설계함
  - Postgres compute 인스턴스는 데이터 소유권을 내려놓고, WAL과 data files를 별도 서비스로 외부화함
  - 이 구조는 Neon 팀이 택한 방향이기도 하고 Lakebase의 기반이 됨

- WAL은 SafeKeeper라는 분산 저장 서비스로 빠짐
  - 로컬 디스크 flush가 아니라, Paxos 기반 네트워크 복제로 SafeKeeper 노드 quorum에 로그 레코드가 복제되면 커밋이 durable하다고 봄
  - 진지한 Postgres HA 구성에서도 synchronous replication을 하려면 어차피 네트워크 hop이 필요하므로, WAL 외부화가 추가 지연을 만든다고 보긴 어렵다는 주장임
  - Databricks는 SafeKeeper와 PageServer 조합이 Postgres 내부 동작상 write throughput을 5배 높이고 read latency를 2배 낮출 수도 있다고 말함

- 데이터 페이지는 PageServer가 맡음
  - SafeKeeper의 WAL 스트림을 PageServer가 받아 object storage에 페이지를 materialize함
  - PageServer는 object storage 앞단의 write-through cache처럼 동작함
  - Postgres가 페이지를 요청했는데 PageServer가 아직 최신 버전을 갖고 있지 않으면, SafeKeeper의 log를 적용해 최신 상태를 재구성함

- 읽기 지연을 줄이는 장치는 다층 캐시임
  - Postgres는 먼저 자기 buffer pool, 즉 로컬 메모리를 확인함
  - 없으면 local disk cache를 보고, 그래도 없을 때만 PageServer로 감
  - compute 노드의 메모리와 디스크 캐시 용량을 기존 모놀리식 구성과 비슷하게 잡을 수 있다면, 대부분의 읽기 지연은 기존 DB와 크게 다르지 않다는 주장임

> [!IMPORTANT]
> Lakebase의 핵심은 “Postgres를 버린다”가 아니라 “Postgres 프로토콜, SQL, 드라이버, 확장은 유지하되 데이터 소유권을 compute 밖으로 뺀다”에 가까움.

## WAL과 page가 분리되면 서버리스, HA, 브랜칭이 자연스럽게 따라온다는 주장

- compute가 stateless에 가까워지면 운영 특성이 확 바뀜
  - idle 상태에서는 scale to zero로 내릴 수 있고, 부하가 오면 compute를 빠르게 띄울 수 있음
  - 데이터는 로컬 디스크 용량이 아니라 cloud object storage에 있으니 실질적으로 unlimited storage에 가까움
  - 개별 compute 노드가 죽어도 durable state는 분산 저장 계층에 남아 있음

- HA도 물리 복제본 중심에서 벗어남
  - 전통 구조에서는 primary 장애에 대비하려면 standby라는 전체 DB 복사본을 유지해야 함
  - Lakebase에서는 durable state가 이미 replicated storage layer에 있으므로, failover가 “다른 물리 복사본을 승격”하는 문제만은 아니게 됨
  - zero data loss를 위해 마지막 WAL segment가 넘어갔는지 조마조마하는 구조를 줄이겠다는 것임

- instant branching과 cloning도 중요한 포인트임
  - 모놀리식 DB에서 production DB를 복제하려면 전체 dataset을 물리적으로 복사해야 해서 느리고 비쌈
  - 외부화된 versioned storage layer에서는 branch나 clone이 metadata operation에 가까워짐
  - 큰 production DB도 몇 초 안에 브랜치해서 위험한 migration이나 실험을 돌리고 버릴 수 있다는 주장임

## LTAP는 한 걸음 더 나가서 Postgres 데이터를 Parquet으로 lake에 둠

- 여기서 Databricks가 꺼내는 키워드가 LTAP, Lake Transactional/Analytical Processing임
  - 목표는 OLTP와 analytics를 하나의 엔진에 억지로 합치는 HTAP가 아님
  - Postgres는 transaction에, Lakehouse engine은 analytics에 계속 쓰되, 밑에 깔린 durable data copy를 하나로 합치자는 접근임
  - CDC, mirroring, zero ETL처럼 별도 복제 파이프라인을 두지 않겠다는 주장임

- PageServer가 데이터를 lake에 materialize하는 순간 row format을 columnar format으로 바꿈
  - Postgres native page format은 row-oriented라 transaction에는 좋지만 analytics에는 별로임
  - LTAP에서는 PageServer가 Postgres 데이터를 object storage에 쓸 때 Parquet columnar layout으로 transcode함
  - durable store는 Delta나 Iceberg 같은 open table format 위의 Parquet으로 놓고, transaction과 analytics 양쪽이 같은 데이터를 보게 함

- Postgres 값을 bit 단위로 보존하려는 설계가 포인트임
  - 대부분의 Postgres type은 Parquet native type으로 직접 매핑됨
  - NaN, ±Infinity, Parquet decimal 범위를 넘는 NUMERIC, 확장 타입처럼 손실 없이 매핑하기 어려운 값은 structured overflow field에 원래 Postgres canonical text를 같이 보관함
  - 목적은 analytics engine이 읽을 수 있으면서도, Postgres-compatible engine이 원래 값을 정확히 재구성할 수 있게 하는 것임

- MVCC도 그냥 버릴 수 없음
  - Postgres는 어떤 트랜잭션이 볼 수 있는 row version을 유지해야 snapshot isolation과 point-in-time recovery가 가능함
  - 반면 Iceberg나 Delta 같은 open table format은 table-wide consistent snapshot을 노출하지, 중간 row version을 그대로 보여주진 않음
  - LTAP는 각 row에 physical heap address, 즉 block과 offset을 실어 heap page를 재구성 가능하게 만들고, 분석 엔진에는 clean snapshot만 보이게 하는 식으로 양쪽 요구를 맞춘다고 설명함

## 최신 데이터 문제는 LSN 기준으로 풀겠다는 설계임

- lake에 아직 materialize되지 않은 방금 전 커밋을 어떻게 볼지가 제일 어려운 문제임
  - 단순히 “analytics가 lake를 읽으면 된다”는 설계는 freshness에서 자주 깨짐
  - LTAP는 분석 쿼리가 시작될 때 먼저 Postgres에서 현재 LSN, 즉 WAL의 정확한 읽기 지점을 받아옴
  - 이건 무거운 쿼리가 아니라 싼 metadata lookup임

- 분석 엔진은 object storage와 PageServer를 합쳐 일관된 최신 스냅샷을 만듦
  - 이미 해당 LSN까지 materialize된 대부분의 데이터는 object storage에서 직접 읽음
  - 아직 lake에 반영되지 않은 아주 최근 변경분만 PageServer에서 가져와 위에 merge함
  - Postgres 자체는 LSN 숫자 하나를 알려주는 것 외에 분석 read traffic을 처리하지 않으므로, 큰 분석 쿼리가 OLTP workload를 느리게 만들지 않는다는 주장임

> [!TIP]
> 이 구조의 실무적 매력은 “분석할 테이블을 CDC 대상으로 골라라”가 아니라, 존재하는 Lakebase 테이블은 구조상 이미 lake에서 쿼리 가능하다는 점임.

## HTAP 대신 storage layer 통합을 고른 이유도 꽤 명확함

- Databricks는 기존 HTAP 접근이 널리 자리 잡지 못한 이유를 세 가지로 봄
  - 새 proprietary engine 하나로 transaction과 analytics를 모두 잘하려면 SQL 기능, optimizer, foreign key 같은 기본기도 오래 걸림
  - Postgres와 Spark가 가진 드라이버, 확장, 도구, 운영 지식 생태계를 새 엔진이 바로 따라가기 어려움
  - transaction과 analytics가 같은 하드웨어에서 돌면 CPU와 메모리 경합이 생겨 성능 격리가 안 됨

- LTAP는 engine이 아니라 storage layer를 통합하는 쪽을 택함
  - transaction은 Postgres가 ACID semantics를 그대로 제공함
  - analytics는 Lakehouse engine이 자기 방식대로 columnar data를 읽음
  - 둘은 compute를 독립적으로 scale하고, 같은 governed copy를 보므로 데이터 drift와 권한 분리 문제를 줄인다는 주장임

- rollout 단계에서는 storage 변경이라 조심스럽게 검증한다고 함
  - Parquet columnar data는 row data보다 보통 10배 이상 잘 압축돼 network transfer와 object store 경로 비용도 줄일 수 있음
  - 전환기에는 검증을 위해 object store에 row format과 columnar format을 dual write한다고 밝힘
  - 작은 테이블은 Iceberg metadata를 만들고 columnar 변환하는 비용이 이득보다 커서 굳이 변환하지 않는 최적화도 둔다고 함

---
## 기술 맥락

- Lakebase가 WAL을 SafeKeeper로 빼는 이유는 커밋 내구성을 로컬 디스크 flush 설정에 맡기지 않기 위해서예요. 운영 DB에서 “디스크가 flush했다고 믿었는데 사실 아니었다”는 식의 실패는 조용히 데이터 손실로 이어질 수 있거든요.

- PageServer는 단순 원격 디스크가 아니라 WAL을 적용해 최신 페이지를 재구성하는 계층이에요. compute는 로컬 캐시로 대부분의 읽기를 처리하고, cache miss일 때만 PageServer에 가기 때문에 기존 Postgres의 성능 감각을 최대한 유지하려는 설계예요.

- LTAP가 CDC 대신 storage layer 통합을 고른 건 두 벌의 데이터가 생기는 순간 지연, drift, 권한 관리 문제가 따라오기 때문이에요. 운영 DB와 분석 lake가 서로 다른 사본이면 “어느 쪽이 진짜 최신인가”를 계속 신경 써야 해요.

- Parquet 변환에서 Postgres 값을 bit 단위로 보존하려는 건 생각보다 큰 제약이에요. 분석 엔진이 읽기 좋은 columnar format으로 바꾸면서도, Postgres의 type system과 MVCC 의미를 깨뜨리면 transaction DB로서 신뢰를 잃기 때문이에요.

- LSN을 기준으로 object storage와 PageServer 변경분을 합치는 방식은 freshness 문제를 풀기 위한 핵심 장치예요. 분석 쿼리는 대부분의 데이터를 싸게 lake에서 읽고, 아직 materialize되지 않은 최신 변경만 PageServer에서 가져와 일관된 스냅샷을 맞추는 구조예요.

## 핵심 포인트

- Lakebase는 Postgres compute를 stateless로 만들고 WAL은 SafeKeeper, 데이터 페이지는 PageServer로 외부화함
- LTAP는 Postgres 데이터가 lake에 materialize될 때 row format을 Parquet columnar layout으로 변환해 분석 엔진이 직접 읽게 함
- 분석 쿼리는 현재 LSN을 기준으로 object storage의 대부분 데이터와 PageServer의 최신 변경분을 합쳐 일관된 최신 스냅샷을 읽음

## 인사이트

Neon식 분리형 Postgres 아키텍처와 Databricks의 Lakehouse를 합쳐 “운영 DB와 분석 lake를 두 벌로 두지 말자”는 주장임. 광고성 톤은 있지만, WAL·PageServer·Parquet·MVCC를 어떻게 맞물리게 하는지 설명이 꽤 깊어서 데이터 인프라 하는 개발자는 볼 가치가 큼.
