PostHog의 DuckDB 데이터 웨어하우스: DuckLake·DuckGres·Firecracker 단일 테넌트로 ClickHouse 다음을 구성한 방법
요약
PostHog는 제품 분석(Product Analytics) SaaS다. 이벤트 수집부터 퍼널, 코호트, A/B 테스트까지 처리하는 핵심 스토리지는 ClickHouse—멀티테넌트 클러스터에서 수십억 건의 이벤트를 실시간으로 집계한다. 이 구조는 이벤트 분석에서 잘 작동했지만, 데이터 엔지니어가 실제로 쓰고 싶은 도구들과는 연결되지 않았다.
2026년 6월 PostHog는 두 번째 스토리지 레이어를 공개했다. ClickHouse를 대체하는 것이 아니라 분리된 데이터 웨어하우스다. 핵심 설계 결정은 세 가지: 단일 테넌트 DuckDB, DuckLake 카탈로그, DuckGres Postgres 와이어 프로토콜. 이 조합이 dbt·BI 도구·표준 드라이버를 PostHog 이벤트 데이터 위에서 그대로 쓸 수 있게 만든다.
- 조직마다 독립된 Firecracker MicroVM 위의 DuckDB 인스턴스
- 저장소는 조직별로 파티셔닝된 S3 — DuckDB와 무관하게 독립 존재
- DuckGres: Postgres wire protocol 서버로 psql·dbt·Metabase·Tableau 직접 연결
- 컴퓨트 절약: 유휴 시 자동 종료(60초), 쿼리 시 300ms 내 재시작
- 2026년 6월 29일 블로그 공개, 웨이팅리스트 베타
문제: ClickHouse 멀티테넌트의 한계
이벤트 분석에서의 ClickHouse
PostHog의 운영 스택은 ClickHouse를 중심으로 설계됐다. 초당 수백만 건의 이벤트를 수집하고, 집계 쿼리를 밀리초 단위로 응답하는 데 ClickHouse는 적합하다. 문제는 이 용도 밖에서 시작됐다.
멀티테넌트 구조의 세 가지 장벽
1. 직접 연결 불가
ClickHouse 클러스터를 여러 고객이 공유하는 멀티테넌트 구조에서는 개별 고객에게 클러스터 직접 연결 권한을 줄 수 없다. 한 고객의 무거운 쿼리가 다른 고객 성능에 영향을 준다. 결과적으로 dbt가 PostHog 데이터에 직접 접근하는 경로가 없었다.
2. 데이터 생태계 도구 미지원
dbt, Metabase, Grafana, Tableau 같은 도구는 PostgreSQL 방언이나 표준 JDBC/ODBC 드라이버를 기대한다. ClickHouse는 고유한 SQL 방언과 프로토콜을 쓴다. 커넥터가 있어도 기능 제한이 크다.
3. 조직 간 데이터 분리 복잡성
멀티테넌트 ClickHouse에서 한 조직의 데이터가 다른 조직의 쿼리에 노출되지 않도록 보장하는 것은 복잡한 행-수준 접근 제어(Row-Level Security) 구현을 요구한다. 실수 하나가 데이터 유출이 된다.
해결: 단일 테넌트 DuckDB 아키텍처
핵심 원칙: 컴퓨트와 스토리지의 완전 분리
Firecracker MicroVM: 테넌트 격리의 하드웨어 경계
PostHog는 조직별 DuckDB 인스턴스를 Firecracker MicroVM 위에서 실행한다. Firecracker는 AWS가 Lambda와 Fargate에 사용하는 경량 가상화 기술이다. Docker 컨테이너보다 강한 커널 수준 격리를 제공하면서, 부팅 시간은 밀리초 단위다.
이 선택의 결과:
- 성능 격리: 한 조직의 무거운 집계 쿼리가 다른 조직 인스턴스에 영향을 주지 않는다.
- 보안 격리: 커널 수준 경계로 크로스-테넌트 메모리 접근이 물리적으로 차단된다.
- 비용 모델: 유휴 인스턴스는 종료된다. 컴퓨트 과금은 쿼리가 실행되는 시간에만 발생한다.
라이프사이클 관리
| 상태 | 조건 | 동작 |
|---|---|---|
| 슬리핑 | 60초 유휴 후 | MicroVM 종료, 비용 중단 |
| 웜업 | 쿼리 도착 | ~300ms 내 MicroVM 시작, DuckDB 초기화 |
| 실행 중 | 쿼리 처리 | DuckDB가 S3에서 필요한 Parquet 파일 읽기 |
| 종료 예약 | 쿼리 완료 후 60s | 연속 쿼리 없으면 종료 |
DuckLake: 컴퓨트에 묶이지 않는 카탈로그
DuckLake는 DuckDB Labs가 만든 오픈소스 Lakehouse 포맷 겸 카탈로그 레이어다(2026-04 GA). PostHog는 DuckLake를 스토리지 카탈로그로 채택해, 데이터를 DuckDB에 종속시키지 않는다.
DuckLake의 역할:
- 카탈로그 관리: 테이블 메타데이터, 스냅샷, 파티션 정보를 SQL 데이터베이스(SQLite·PostgreSQL·DuckDB 중 선택)에 저장.
- Iceberg REST Catalog 호환: Trino, Spark, Flink 같은 다른 엔진도 동일한 데이터에 접근 가능.
- 스토리지 독립성: 데이터는 S3에 Parquet로 존재한다. DuckDB를 교체해도 데이터를 다시 마이그레이션할 필요가 없다.
PostHog의 표현: "DuckLake가 있어서 DuckDB에 영원히 묶이지 않는다."
DuckGres: PostgreSQL 껍데기를 두른 DuckDB
왜 Postgres 프로토콜인가
데이터 생태계의 대부분 도구는 Postgres 방언과 Postgres 와이어 프로토콜을 이해한다. dbt에는 수십 개의 Postgres 어댑터가 있다. Metabase·Grafana·Tableau는 Postgres 연결 설정을 기본으로 제공한다.
DuckGres는 DuckDB 앞에 Postgres 인터페이스를 제공하는 오픈소스 서버다. 쿼리가 들어오면:
- Postgres 파서로 파싱: Postgres 문법을 DuckDB SQL로 변환
- DuckDB 폴백: 파싱 실패 시 DuckDB에서 직접
EXPLAIN으로 유효성 검증
세 가지 배포 모드:
- 독립형(Standalone): 단일 프로세스로 모든 처리
- 컨트롤플레인(Control-plane): 관리자와 워커 풀이 Arrow Flight SQL로 통신하는 멀티프로세스 구조
- 원격 워커(Remote Worker): Kubernetes 네이티브, 분산 워커
PostHog 웨어하우스의 DuckGres가 지원하는 도구:
| 카테고리 | 도구 |
|---|---|
| BI | Metabase, Grafana, Superset, Tableau |
| 변환 | dbt (모든 어댑터) |
| SQL 클라이언트 | psql, DBeaver, DataGrip |
| 언어 드라이버 | JDBC, ODBC, Python psycopg2/asyncpg |
DuckHog: 로컬에서 웨어하우스 데이터 다루기
DuckHog는 로컬 DuckDB에 설치하는 확장이다. 웨어하우스 데이터의 일부 서브셋을 로컬로 내려받아 개발하고, 결과를 다시 웨어하우스에 쓸 수 있다.
-- 로컬 DuckDB에서 PostHog 웨어하우스 연결
LOAD duckhog;
CALL duckhog.connect('my-org-token');
-- S3에 있는 이벤트 데이터 로컬 쿼리
SELECT event, count(*) FROM posthog.events
WHERE toDate(timestamp) = today()
GROUP BY event ORDER BY 2 DESC;개발자가 Pandas, Polars, DuckDB로 직접 분석하다가 결과를 웨어하우스에 쓰는 워크플로우를 지원한다.
ClickHouse와 DuckDB: 다른 역할, 다른 자리
PostHog는 ClickHouse를 버리지 않았다. 두 엔진이 명확하게 다른 역할을 맡는다.
이 분리 전략은 PostHog만의 선택이 아니다. 이벤트 스트림을 ClickHouse로 빠르게 처리하면서, 구조화된 분석 레이어를 표준 SQL 도구로 구성하는 패턴은 데이터 플랫폼 설계에서 점점 일반화되고 있다.
운영 체크리스트: 유사 아키텍처를 고려할 때
PostHog의 설계에서 배울 수 있는 일반 원칙과 검토 사항:
저장소-컴퓨트 분리를 전제로 설계하라
- 데이터는 S3에 Parquet로. 쿼리 엔진은 교체 가능한 레이어.
- DuckLake처럼 엔진 독립 카탈로그를 쓰면 마이그레이션 비용이 크게 줄어든다.
단일 테넌트 격리의 비용을 먼저 계산하라
- Firecracker MicroVM은 강한 격리를 주지만, 인스턴스 시작 비용(300ms)이 있다.
- 짧은 쿼리가 빈번한 워크로드에서는 웜업 지연이 체감된다. 슬리핑 정책(60초)을 조정 가능한지 확인.
Postgres 호환 레이어의 기능 갭을 점검하라
- DuckGres는 Postgres SQL을 DuckDB SQL로 변환한다. 변환되지 않는 함수나 시스템 카탈로그 쿼리가 있을 수 있다.
- 도구별 연동 전 쿼리 호환성 테스트를 선행하라.
데이터 신선도 모델을 명확히 정의하라
- PostHog 이벤트 데이터는 ClickHouse에서 S3로 미러링된다. 미러 지연(수 초~수 분)이 발생한다.
- 실시간이 필요한 쿼리는 ClickHouse, 일 단위 이상 분석은 DuckDB 웨어하우스로 역할을 나눠라.
한계와 현재 상태
| 항목 | 상태 | 설명 |
|---|---|---|
| 웨어하우스 GA | 베타 (웨이팅리스트) | 2026년 6월 기준, 전체 공개 아님 |
| 웜업 지연 | ~300ms | 슬리핑 인스턴스 재시작 비용 |
| ClickHouse 미러 지연 | 수 초~수 분 | 실시간 분석에 부적합 |
| DuckGres SQL 호환성 | Postgres 방언 부분 지원 | 복잡한 시스템 카탈로그 쿼리 미지원 가능 |
| DuckLake 성숙도 | 1.0 GA (2026-04) | Iceberg REST 호환은 DuckDB 1.5.3+ 필요 |
Open Question
- Firecracker MicroVM 수백 개를 동시에 관리하는 오케스트레이션 레이어는 어떻게 구성되어 있는가?
- S3 → ClickHouse → DuckDB 미러 파이프라인의 지연 보장치는 SLA로 명시되어 있는가?
- DuckGres의 Arrow Flight SQL 멀티프로세스 모드는 어느 규모부터 필요한가?
- DuckLake Iceberg REST 카탈로그를 Trino·Spark에서 직접 쿼리하는 운영 패턴이 지원되는가?
References
- PostHog 블로그 (2026-06-29): "Why we rebuilt our data warehouse on DuckDB" — https://posthog.com/blog/why-we-rebuilt-our-data-warehouse
- GitHub — PostHog/duckgres: DuckDB Postgres Server — https://github.com/PostHog/duckgres
- GitHub — PostHog/duckhog: DuckDB extension for PostHog warehouse — https://github.com/PostHog/duckhog
- DuckLake 1.0 (2026-04-13) — SQL catalog backed by standard databases, Iceberg REST Catalog compat
- PostHog Managed Warehouse docs — https://posthog.com/data-stack/managed-warehouse
- arXiv:2504.15247 — Lance format 2.x paper (관련: DuckDB 위의 벡터 레이크하우스 패턴)