LLM WikiAccess-protected knowledge portal
← 스터디 홈
133편 · 약 14분

DuckDB 2.0 Cyanoptera 프리뷰: 비동기 I/O·클라이언트-서버·VARIANT 샤딩·트리거로 달라지는 운영 경계

요약

2026년 8월 17일 DuckDB 팀이 v2.0(코드명 Cyanoptera)의 주요 변화를 공개했다. 정식 릴리스는 2026년 가을 예정이며, 현재 나이틀리 빌드로 미리 사용 가능하다. v1.5(2026년 3월) 이후 10,000개 이상의 커밋이 쌓인 이 버전은 DuckDB를 단순한 인프로세스 분석 엔진에서 네트워크 서빙이 가능한 멀티클라이언트 OLAP 플랫폼으로 확장한다.

핵심 변화 네 가지:

  1. 비동기 I/O: S3 쿼리 887초 → 45초(약 20배), 일부 워크로드 최대 40배 향상
  2. 클라이언트-서버 모드: Quack 익스텐션 + CONNECT 문으로 DuckDB 프로세스가 네트워크 서버로 동작
  3. VARIANT 타입 완성: 자동 샤딩(shredding) + Parquet 연동 + variant_* 함수군
  4. 트리거 전면 지원: BEFORE/AFTER, 행/문 수준, 전환 테이블

배경: 왜 DuckDB 2.0이 필요한가

DuckDB 1.x의 설계 전제는 "단일 프로세스, 단일 클라이언트"였다. 이 제약 덕분에 락 없는 구조, 네트워크 오버헤드 제거, 임베딩 단순성이 가능했다. 그러나 두 가지 한계가 점점 두드러졌다.

첫째, 원격 스토리지 성능. AWS EC2에서 S3의 Parquet을 쿼리할 때 동기 I/O는 스레드를 블로킹 상태로 유지한다. 쿼리 처리 능력이 아무리 뛰어나도 I/O 대기 시간이 지배적이 되면 성능이 나오지 않는다. 로컬 SSD에서의 빠른 속도가 클라우드 환경에서 재현되지 않는 이유다.

둘째, 멀티클라이언트 수요. 단일 분석 세션이 아니라 여러 서비스가 같은 DuckDB 데이터베이스를 동시에 읽어야 하는 시나리오가 늘었다. 1.x에서는 WAL 잠금 때문에 불가능했다.

v2.0은 이 두 문제를 구조적으로 해결한다.


변화 1: 비동기 I/O

아키텍처 전환

이전까지 DuckDB의 원격 파일 읽기는 동기적이었다. 워커 스레드가 S3 GET 요청을 보내고 응답이 올 때까지 블로킹됐다. 병렬 읽기는 가능했지만 각 스레드가 독립적으로 대기했다.

v2.0은 I/O 레이어와 쿼리 처리 레이어를 완전히 분리했다. 전용 I/O 스레드 풀이 비동기 읽기를 처리하고, 쿼리 워커는 데이터가 준비되면 재개된다. 이 구조는 대역폭이 충분한 환경에서 특히 효과적이다.

실측 수치

AWS EC2에서 S3의 CSV 데이터셋 쿼리 시:

  • DuckDB 1.x (동기): 887초
  • DuckDB 2.0 (비동기): 45초
  • 향상 배율: 약 20배

Parquet 워크로드와 I/O 집중 쿼리에서는 최대 40배 향상이 측정됐다. 로컬 NVMe 쿼리에서는 차이가 크지 않다. 병목이 이미 디스크가 아닌 CPU이기 때문이다.

지원 포맷

v2.0부터 비동기 읽기를 지원하는 포맷:

  • Parquet
  • CSV
  • (향후 확장 예정)

변화 2: 클라이언트-서버 모드

Quack 익스텐션

DuckDB v2.0은 Quack 익스텐션을 통해 클라이언트-서버 모드를 제공한다. 기존 DuckDB 프로세스가 새 CONNECT 문을 통해 네트워크 서버 역할을 할 수 있다.

-- 서버 측: DuckDB 프로세스를 서버로 기동
LOAD quack;
SERVE DATABASE my_analytics.duckdb ON PORT 5432;

-- 클라이언트 측: 다른 DuckDB 프로세스에서 연결
CONNECT 'duckdb://server-host:5432/my_analytics';
SELECT count(*) FROM events WHERE date >= '2026-08-01';

이 모드는 여러 클라이언트가 동일한 DuckDB 데이터베이스를 동시에 읽는 시나리오를 지원한다. 쓰기 동시성은 여전히 제한적이다. DuckDB의 ACID 보증이 단일 서버 내에서 유지된다.

언제 쓰고 언제 쓰지 말아야 하나

적합한 시나리오:

  • 여러 데이터 과학자가 같은 Parquet/Iceberg 카탈로그를 쿼리하는 팀 환경
  • 마이크로서비스가 DuckDB 기반 분석 레이어에 읽기 전용으로 접근
  • 경량 OLAP API 서버

부적합한 시나리오:

  • 고빈도 동시 쓰기 (이 경우 PostgreSQL, ClickHouse가 적합)
  • 글로벌 분산 클러스터 (Trino, Spark가 적합)

변화 3: VARIANT 타입 완성

VARIANT란

VARIANT는 반정형(semi-structured) 데이터를 위한 네이티브 타입이다. JSON, 로그, 이벤트 스트림처럼 스키마가 유동적인 데이터를 저장한다.

v1.x에서도 기초 지원이 있었지만, v2.0에서 자동 샤딩(automatic shredding) 이 완성됐다.

자동 샤딩 원리

샤딩은 VARIANT 컬럼 안에서 반복적으로 나타나는 구조를 탐지해 컬럼형으로 분리 저장하는 최적화다.

-- events 테이블의 payload 컬럼이 VARIANT 타입
CREATE TABLE events (
    ts TIMESTAMP,
    payload VARIANT
);

INSERT INTO events VALUES
    ('2026-08-23', {'user_id': 42, 'action': 'click', 'value': 1.5}),
    ('2026-08-23', {'user_id': 43, 'action': 'view',  'value': 0.0});

-- v2.0: 자동으로 user_id, action, value를 컬럼으로 샤딩
-- 쿼리 시 전체 JSON 파싱 없이 컬럼 직접 접근
SELECT payload->>'action', avg((payload->>'value')::FLOAT)
FROM events
GROUP BY 1;

샤딩된 데이터는 Parquet으로 읽고 쓸 수 있다. extraction pushdown이 지원되어 스캔 단계에서 필요한 필드만 추출한다.

variant_* 함수군

v2.0은 VARIANT를 다루는 함수를 대폭 확장했다.

-- 타입 확인
SELECT variant_typeof(payload) FROM events;

-- 중첩 접근
SELECT variant_extract(payload, '$.metadata.region') FROM events;

-- 배열 분해
SELECT unnest(variant_list_elements(payload->'tags')) FROM events;

변화 4: 트리거

DuckDB는 1.x까지 트리거를 지원하지 않았다. v2.0에서 완전한 SQL 표준 트리거 구현을 추가했다.

지원 범위

기능지원 여부
BEFORE / AFTER 트리거
FOR EACH ROW (행 수준)
FOR EACH STATEMENT (문 수준)
전환 테이블 (REFERENCING OLD/NEW TABLE)
이벤트당 다중 트리거
RETURNING on triggered tables
DROP TRIGGER
-- 변경 감사 테이블
CREATE TABLE audit_log (
    ts TIMESTAMP DEFAULT now(),
    table_name TEXT,
    operation TEXT,
    old_row VARIANT,
    new_row VARIANT
);

-- 행 수준 AFTER 트리거
CREATE TRIGGER orders_audit
AFTER UPDATE ON orders
FOR EACH ROW
BEGIN
    INSERT INTO audit_log(table_name, operation, old_row, new_row)
    VALUES ('orders', 'UPDATE', to_variant(OLD), to_variant(NEW));
END;

새 SQL 파서와 스토리지 포맷

SQL 파서 재작성

v2.0은 SQL 파서를 처음부터 다시 작성했다. 목표는 세 가지였다.

  1. PostgreSQL 호환성 향상: DISTINCT ON, window function, recursive CTE 등 고급 SQL의 파싱 정확도 개선
  2. 에러 메시지 품질: 잘못된 SQL에서 정확한 위치와 원인을 알려주는 진단 메시지
  3. 확장성: 향후 DDL/DML 문법 추가를 위한 구조적 기반

새 스토리지 포맷

v2.0의 기본 스토리지 포맷은 인덱스가 많거나 컬럼이 많은("wide") 테이블의 열기(open) 시간과 메모리를 크게 줄인다. 구체적인 수치는 GA 릴리스 노트에서 확인 예정이다.

주의: v1.x로 작성된 .duckdb 파일은 v2.0에서 읽을 수 있지만, v2.0으로 쓴 파일은 v1.x에서 열리지 않는다. 팀 환경에서 마이그레이션 계획이 필요하다.

C API 재작성

v2.0은 C API를 대폭 변경했다. 기존 C 바인딩을 직접 사용하는 코드는 수정이 필요하다. Python, R, Node.js 등 공식 SDK는 팀이 대응 업데이트를 제공하므로 대부분의 사용자는 영향이 적다.


아키텍처 변화 다이어그램

DuckDB 아키텍처 변화 — v1.x vs v2.0 v1.x — 동기 I/O, 단일 클라이언트 클라이언트 (단일) 쿼리 처리 워커 스레드 블로킹 동기 I/O S3 GET → 대기 → 다음 원격 스토리지 S3 / GCS ※ 887초 (S3 CSV 벤치마크) ※ 클라이언트 동시 접속 불가 v2.0 — 비동기 I/O, 멀티 클라이언트 클라이언트1 클라이언트2 클라이언트N Quack 서버 CONNECT 멀티클라이언트 쿼리 처리 워커 비블로킹 비동기 I/O 레이어 전용 I/O 스레드 풀 ※ 45초 (동일 S3 벤치마크, ~20배 향상) ※ 멀티 클라이언트 동시 읽기 지원 v2.0 주요 신규 기능 VARIANT 타입 • 자동 샤딩 — 반복 구조 컬럼화 • Parquet 읽기/쓰기 완성 • extraction pushdown 트리거 • BEFORE / AFTER • FOR EACH ROW / STATEMENT • 전환 테이블 REFERENCING SQL 파서 재작성 • PostgreSQL 호환성 향상 • 정확한 에러 위치/원인 • 10,000+ 커밋 누적 새 스토리지 포맷 • wide table 열기 가속 • 대형 인덱스 메모리 절감 • C API 재작성 (breaking) * 코드명 Cyanoptera | 프리뷰: 나이틀리 빌드 | GA 예정: 2026년 가을
DuckDB 1.x vs 2.0 — I/O 아키텍처와 서버 모드 비교

운영자 관점 — 무엇을 준비해야 하는가

1. 비동기 I/O: 클라우드 환경 즉시 이득

원격 스토리지(S3, GCS, Azure Blob)를 사용하는 워크로드라면 v2.0으로 업그레이드만 해도 대기 없이 성능 향상이 따라온다. 로컬 파일 쿼리는 변화가 크지 않다.

2. 스토리지 포맷 호환성 확인

# v1.x 데이터베이스를 v2.0으로 열 수 있는지 확인
duckdb --version   # 2.0.x 이상인지 확인
duckdb my_db.duckdb -c "PRAGMA version;"

팀원 중 일부가 v1.x를 계속 사용해야 한다면, 데이터베이스 파일을 v2.0으로 쓰는 순간 v1.x에서 열 수 없다. 마이그레이션 계획이 필요하다.

3. C API 바인딩 점검

직접 C API를 호출하는 코드(커스텀 익스텐션, 임베딩)는 v2.0에서 컴파일 오류가 날 수 있다. Python duckdb 패키지, R duckdb 패키지, node-duckdb 등 공식 바인딩은 팀이 업데이트 제공 예정이다.

4. 클라이언트-서버 모드의 한계

Quack 서버 모드는 아직 프리뷰 단계다. 동시 쓰기가 많은 워크로드, HA가 필요한 프로덕션 환경에는 아직 적합하지 않다. 읽기 중심 팀 분석 환경이나 API 레이어에서 먼저 평가하는 것이 안전하다.

5. VARIANT 마이그레이션

기존에 JSON 컬럼으로 저장하던 반정형 데이터를 VARIANT로 전환하면 쿼리 성능이 향상될 수 있다. 샤딩은 자동이지만, 기존 JSON 파싱 쿼리(json_extract, ->, ->>)는 variant_extract->>(VARIANT 버전)로 검토가 필요하다.


체크리스트: v2.0 도입 전 확인사항

  • [ ] 현재 DuckDB 버전 확인 (SELECT version())
  • [ ] 팀 전체가 같은 버전을 쓰고 있는지 확인 — 포맷 비호환 주의
  • [ ] 원격 스토리지(S3/GCS) 사용 중이면 나이틀리 빌드로 먼저 성능 측정
  • [ ] C API 직접 사용 코드 점검 — duckdb_open, duckdb_query 등 시그니처 변화 확인
  • [ ] JSON 컬럼을 VARIANT로 전환할 경우 쿼리 호환성 테스트
  • [ ] 클라이언트-서버 모드가 필요하다면 Quack 익스텐션 설치 확인
  • [ ] GA 전까지 프로덕션 배포 자제 — 스토리지 포맷이 안정화 전에 변경될 수 있음

열린 질문

Open question: 클라이언트-서버 모드에서 동시 쓰기 처리 방식과 WAL 잠금 범위가 아직 공식 문서에 명확히 없다. GA 릴리스 노트 확인 필요.

Open question: 새 스토리지 포맷의 파일 크기 변화가 공개되지 않았다. v1.x 대비 더 크거나 작을 수 있으며 사용 패턴에 따라 다를 것으로 예상된다.


References

  • DuckDB 공식 블로그, A Preview of DuckDB v2.0 (2026-08-17): https://duckdb.org/2026/08/17/duckdb-20-highlights
  • DuckDB 공식 블로그, Asynchronous I/O in DuckDB (2026-07-31): https://duckdb.org/2026/07/31/asynchronous-io
  • InfoWorld, DuckDB 2.0 coming this fall with client/server mode: https://www.infoworld.com/article/4210635/duckdb-2-0-coming-this-fall-with-client-server-mode.html
  • DuckDB GitHub, VARIANT shredding discussion: https://github.com/duckdb/duckdb/discussions/20040
  • The Stack Technology, Server mode, triggers, and SQL — DuckDB teases V2.0: https://www.thestack.technology/server-mode-triggers-and-sql-duckdb-teases-v2-0/
  • DuckDB release calendar: https://duckdb.org/release_calendar
  • DuckDB 1.5.0 announcement (for context): https://duckdb.org/2026/03/09/announcing-duckdb-150