https://2stndard.tistory.com/notice/203
[발간예정][EPL과 유튜브로 배우는 DuckDB] 실습 코드와 데이터
EPL과 유튜브 데이터로 배우는 DuckDB에서 사용되는 실습 데이터와 코드를 제공합니다. EPL_DATA&samplefile.zip : 책에서 사용하는 영국 프리미어리그 데이터 셋과 샘플로 사용하는 파일espn.duckdb.zip : 책
2stndard.tistory.com
<출처: DuckLake Blog, https://ducklake.select/manifesto/>
저자: Mark Raasveldt and Hannes Mühleisen
이 블로그는 Ducklake를 만든 개발팀에서 Ducklake의 초기 개발 사상과 개발 방향에 대한 선언문으로 만든 글을 번역한 블로그입니다. 따라서 다소 함축적이고 추상적인 개념들이 설명되어 있다은 점을 참고 바랍니다.
DuckLake는 복잡한 파일 기반 시스템 대신 모든 메타데이터에 표준 SQL 데이터베이스를 사용하면서도, 데이터는 여전히 Parquet와 같은 개방형 형식으로 저장함으로써 레이크하우스(lakehouse)를 간소화합니다. 이를 통해 더 높은 신뢰성과 빠른 처리 속도, 그리고 손쉬운 관리 기능을 제공합니다.
이 선언문의 내용을 음성으로 들어보시겠습니까? DuckLake 형식을 어떻게 고안하게 되었는지 설명하는 팟캐스트 에피소드도 공개했습니다.
배경
BigQuery나 Snowflake와 같은 혁신적인 데이터 시스템들은 스토리지가 가상화된 범용 자원이 된 오늘날, 스토리지와 컴퓨팅을 분리하는 것이 훌륭한 아이디어임을 입증했습니다. 이를 통해 스토리지와 컴퓨팅을 각각 독립적으로 확장할 수 있으며, 결코 읽지 않을 테이블을 저장하기 위해 고가의 데이터베이스 서버를 구매할 필요가 없어집니다.
동시에 시장 환경은 단일 벤더에 의한 데이터 인질극이라는 흔한 문제를 피하기 위해 데이터 시스템이 Parquet과 같은 개방형 형식을 사용해야 한다고 주장하게 만들었습니다. 이러한 새로운 환경에서 수많은 데이터 시스템은 Parquet과 S3를 기반으로 구축된 깨끗한 “데이터 레이크” 위에서 즐겁게 돌아다니며 모든 것이 순조로웠습니다. 어차피 구식 데이터베이스는 누가 필요하겠습니까!
하지만 곧 충격적인 사실이 드러났습니다. 바로 사람들이 데이터셋을 수정하고 싶어 한다는 것이었습니다. 폴더에 파일을 추가하는 단순한 방식은 꽤 잘 작동했지만, 그 이상의 작업은 정확성이나(코드, 조심하라!) 트랜잭션 보장이 전혀 없는, 복잡하고 오류가 발생하기 쉬운 사용자 정의 스크립트를 필요로 했습니다.
Iceberg와 Delta
데이터 레이크 내 데이터를 변경하는 기본적인 과제를 해결하기 위해 다양한 새로운 개방형 표준이 등장했는데, 그중에서도 Apache Iceberg와 Linux Foundation의 Delta Lake가 가장 두드러집니다. 두 형식 모두 ‘블롭 스토리지에 개방형 형식을 사용한다’는 기본 전제를 포기하지 않으면서도, 테이블에 변경 사항을 적용하는 과정을 어느 정도 합리적으로 만들 수 있도록 설계되었습니다. 예를 들어, 아이스버그는 JSON 및 아브로(Avro) 파일의 복잡한 구조를 사용하여 스키마, 스냅샷, 그리고 특정 시점에 테이블의 일부를 구성하는 파케이(Parquet) 파일을 정의합니다. 그 결과물은 '레이크하우스(lakehouse)'라는 이름으로 불리게 되었으며, 이는 사실상 데이터 레이크에 데이터베이스 기능을 추가한 것으로, 엔진 간 데이터 공유와 같은 데이터 관리를 위한 수많은 새롭고 흥미로운 사용 사례를 가능하게 했습니다.

하지만 두 방식 모두 한 가지 난관에 부딪혔습니다. 일관성 보장이 불안정한 BLOB 저장소에서는 테이블의 최신 버전을 찾는 것이 까다롭기 때문입니다. 모든 사용자가 최신 버전을 볼 수 있도록 포인터를 원자적으로(ACID의 ‘A’) 교체하는 것도 쉽지 않습니다. 또한 Iceberg와 Delta Lake는 사실상 단일 테이블만 처리할 수 있지만, 놀랍게도 사용자들은 여러 테이블을 관리하기를 원했습니다.
카탈로그
해결책은 또 다른 기술 계층을 추가하는 것이었습니다. 즉, 다양한 파일 위에 카탈로그 서비스를 구축한 것입니다. 이 카탈로그 서비스는 모든 테이블 폴더 이름을 관리하는 데이터베이스와 연동됩니다. 또한 각 테이블마다 현재 버전 번호만 포함된, 역사상 가장 초라한 테이블도 관리합니다. 이제 우리는 그 번호를 업데이트할 때 데이터베이스가 제공하는 트랜잭션 보장을 활용할 수 있게 되었고, 모두가 만족하게 되었습니다.

데이터베이스라고요?
하지만 문제는 이렇습니다. Iceberg와 Delta Lake는 애초에 데이터베이스가 필요 없도록 특별히 설계되었습니다. 개발자들은 테이블을 효율적으로 읽고 업데이트하는 데 필요한 모든 정보를 BLOB 스토어의 파일에 담기 위해 많은 노력을 기울였습니다. 이를 달성하기 위해 많은 타협점을 두었습니다. 예를 들어, Iceberg의 모든 루트 파일에는 스키마 정보 등을 포함한 기존 스냅샷이 모두 담겨 있습니다. 변경 사항이 발생할 때마다 전체 이력을 포함하는 새로운 파일이 생성됩니다. 블롭 스토어에서는 비효율적인 너무 많은 작은 파일을 쓰거나 읽는 것을 피하기 위해, 예를 들어 2계층 매니페스트 파일과 같이 다른 많은 메타데이터를 묶어서 처리해야 했습니다. 데이터에 대한 작은 변경을 가하는 것 또한 여전히 잘 이해되지 않거나 오픈소스 구현체에서 제대로 지원되지 않는 복잡한 정리 절차를 필요로 하는, 대체로 해결되지 않은 문제입니다. 빠르게 변화하는 데이터를 관리하는 이 문제를 해결하기 위해 전담 기업들이 존재하며, 지금도 계속해서 설립되고 있습니다. 마치 일종의 전문 데이터 관리 시스템을 도입하는 것이 좋은 아이디어인 것처럼 보입니다.
하지만 앞서 지적했듯이, Iceberg와 Delta Lake 설계는 일관성을 위해 이미 타협을 통해 카탈로그의 일부로 데이터베이스를 추가해야 했습니다. 그러나 이들은 이러한 근본적인 설계 변경에 맞춰 나머지 설계 제약 조건과 기술 스택을 재검토하지는 않았습니다.
DuckLake
DuckDB 팀은 사실 데이터베이스를 정말 좋아합니다. 데이터베이스는 상당히 방대한 데이터 세트를 안전하고 효율적으로 관리할 수 있는 놀라운 도구입니다. 어차피 데이터베이스가 레이크하우스 스택에 도입되었다면, 나머지 테이블 메타데이터를 관리하는 데에도 이를 활용하는 것이 정말로 이치에 맞습니다! 우리는 여전히 Parquet와 같은 개방형 형식으로 실제 테이블 데이터를 저장할 때 BLOB 스토어의 “무한한” 용량과 “무한한” 확장성을 활용할 수 있지만, 데이터베이스 내 변경 사항을 지원하는 데 필요한 메타데이터는 훨씬 더 효율적이고 효과적으로 관리할 수 있습니다! 우연히도, 이는 Google BigQuery(Spanner 사용)와 Snowflake(FoundationDB 사용)가 선택한 방식이기도 합니다. 다만 하단 계층에 개방형 형식을 사용하지 않을 뿐이죠.

기존 레이크하우스 아키텍처의 근본적인 문제점을 해결하기 위해, ‘DuckLake’라는 새로운 오픈 테이블 형식을 개발했습니다. DuckLake는 다음 두 가지 간단한 사실을 바탕으로 ‘레이크하우스’ 형식이 어떤 모습이어야 하는지를 재구상합니다.
- 데이터 파일을 블롭 스토리지에 오픈 형식으로 저장하는 것은 확장성을 확보하고 벤더 종속성을 방지하는 데 매우 효과적인 방법입니다.
- 메타데이터 관리는 복잡하고 상호 연결된 데이터 관리 작업이므로, 데이터베이스 관리 시스템에 맡기는 것이 가장 좋습니다.
DuckLake의 기본 설계는 카탈로그 데이터와 테이블 데이터를 모두 SQL 데이터베이스로 통합하는 것입니다. 이 형식은 관계형 테이블 집합과, 스키마 생성, 수정, 데이터 추가, 삭제 및 업데이트와 같은 데이터 작업을 기술하는 순수 SQL 트랜잭션으로 정의됩니다. DuckLake 형식은 테이블 간 트랜잭션을 통해 임의의 수의 테이블을 관리할 수 있습니다. 또한 뷰, 중첩형, 트랜잭션 기반 스키마 변경 등과 같은 "고급" 데이터베이스 개념도 지원합니다. 자세한 목록은 아래를 참조하십시오. 이 설계의 주요 장점 중 하나는 참조 일관성(ACID의 "C")을 활용함으로써, 스키마가 예를 들어 중복된 스냅샷 ID가 없도록 보장한다는 점입니다.

어떤 SQL 데이터베이스를 사용할지는 사용자의 선택에 달려 있으며, 유일한 요구 사항은 시스템이 표준 SQL을 지원할 뿐만 아니라 ACID 연산과 기본 키를 지원해야 한다는 점입니다. DuckLake 내부 테이블 스키마는 다양한 SQL 데이터베이스와의 호환성을 극대화하기 위해 의도적으로 단순하게 설계되었습니다. 다음은 예시를 통해 살펴본 핵심 스키마입니다.
새롭고 빈 테이블에 다음 쿼리를 실행할 때 DuckLake 내에서 발생하는 쿼리 순서를 살펴보겠습니다:
INSERT INTO demo VALUES (42), (43);
BEGIN TRANSACTION;
-- some metadata reads skipped here
INSERT INTO ducklake_data_file
VALUES (0, 1, 2, NULL, NULL, 'data_files/ducklake-8196...13a.parquet', 'parquet', 2, 279, 164, 0, NULL, NULL);
INSERT INTO ducklake_table_stats
VALUES (1, 2, 2, 279);
INSERT INTO ducklake_table_column_stats
VALUES (1, 1, false, NULL, '42', '43');
INSERT INTO ducklake_file_column_statistics
VALUES (0, 1, 1, NULL, 2, 0, 56, '42', '43', NULL)
INSERT INTO ducklake_snapshot
VALUES (2, now(), 1, 2, 1);
INSERT INTO ducklake_snapshot_changes
VALUES (2, 'inserted_into_table:1');
COMMIT;
다음과 같은 단일하고 일관된 SQL 트랜잭션이 수행됩니다.
- 새로운 Parquet 파일 경로를 삽입합니다.
- 전역 테이블 통계를 업데이트합니다(이제 행 수가 늘어났습니다).
- 전역 열 통계를 업데이트합니다(이제 최소값과 최대값이 달라졌습니다).
- 파일 열 통계를 업데이트합니다(최소값/최대값 등도 기록합니다).
- 새로운 스키마 스냅샷(#2)을 생성합니다.
- 스냅샷에서 발생한 변경 사항을 기록합니다.
Parquet에 대한 실제 쓰기 작업은 이 순서의 일부가 아니며, 그보다 앞서 수행된다는 점에 유의하십시오. 하지만 값이 몇 개 추가되든 이 순서의 처리 비용은 동일하게(낮게) 유지됩니다.
이제 DuckLake의 세 가지 원칙인 단순성, 확장성, 속도에 대해 살펴보겠습니다.
간결성
DuckLake는 단순성과 점진적 확장을 지향하는 DuckDB의 설계 원칙을 따릅니다. 노트북에서 DuckLake를 실행하려면 ducklake 확장 기능을 포함한 DuckDB만 설치하면 됩니다. 이는 테스트, 개발 및 프로토타이핑에 매우 유용합니다. 이 경우 카탈로그 저장소는 단순히 로컬 DuckDB 파일로 구성됩니다.
다음 단계는 외부 스토리지 시스템을 활용하는 것입니다. DuckLake 데이터 파일은 불변(immutable)이므로, 파일을 직접 수정하거나 파일 이름을 재사용할 필요가 전혀 없습니다. 덕분에 거의 모든 스토리지 시스템에서 사용할 수 있습니다. DuckLake는 로컬 디스크, 로컬 NAS, S3, Azure Blob Store, GCS 등 모든 스토리지 시스템과의 연동을 지원합니다. 데이터 파일의 스토리지 접두사(예: s3://mybucket/mylake/)는 메타데이터 테이블을 생성할 때 지정합니다.
마지막으로, 카탈로그 서버를 호스팅하는 SQL 데이터베이스는 ACID 및 기본 키 제약 조건을 지원하는 어느 정도 수준만 갖춘 SQL 데이터베이스라면 무엇이든 가능합니다. 대부분의 조직은 이미 이러한 시스템을 운영한 풍부한 경험을 가지고 있을 것입니다. SQL 데이터베이스 외에 추가적인 소프트웨어 스택이 필요하지 않으므로 배포가 크게 간소화됩니다. 또한, 최근 몇 년간 SQL 데이터베이스는 대중화되어, 카탈로그 저장소로 사용할 수 있는 수많은 호스팅형 PostgreSQL 서비스나 심지어 호스팅형 DuckDB까지 존재합니다! 다시 말해, 테이블 데이터 이동이 필요 없고 스키마가 단순하며 표준화되어 있기 때문에, 여기서의 종속성은 매우 제한적입니다.
Avro나 JSON 파일은 없습니다. 통합해야 할 별도의 카탈로그 서버나 추가 API도 없습니다. 모든 것이 단순히 SQL로 이루어져 있습니다. 우리 모두 SQL을 알고 있습니다.
확장성
DuckLake는 데이터 아키텍처 내의 관심사 분리를 세 가지 부분으로 더욱 명확하게 구분합니다. 바로 스토리지, 컴퓨팅, 메타데이터 관리입니다. 스토리지는 전용 파일 스토리지(예: BLOB 스토리지)에 유지되며, DuckLake는 스토리지 측면에서 무한한 확장이 가능합니다.
임의의 수의 컴퓨팅 노드가 카탈로그 데이터베이스에 쿼리를 실행하고 업데이트한 후, 스토리지에서 독립적으로 데이터를 읽고 씁니다. DuckLake는 컴퓨팅 측면에서도 무한한 확장이 가능합니다.
마지막으로, 카탈로그 데이터베이스는 컴퓨팅 노드에서 요청한 메타데이터 트랜잭션만 처리할 수 있어야 합니다. 이러한 트랜잭션의 양은 실제 데이터 변경량보다 몇 배나 적습니다. 하지만 DuckLake는 단일 카탈로그 데이터베이스에 국한되지 않으므로, 수요가 증가함에 따라 예를 들어 PostgreSQL에서 다른 시스템으로 마이그레이션하는 것이 가능합니다. 결국 DuckLake는 간단한 테이블과 기본적이며 이식성 높은 SQL을 사용합니다. 하지만 걱정하지 마세요. PostgreSQL을 기반으로 하는 DuckLake만으로도 이미 수백 테라바이트의 데이터와 수천 개의 컴퓨트 노드로 확장할 수 있습니다.
다시 말해, 이는 이미 방대한 데이터 세트를 성공적으로 관리하고 있는 BigQuery와 Snowflake가 사용하는 것과 똑같은 설계입니다. 그리고 필요에 따라 DuckLake 카탈로그 데이터베이스로 Spanner를 사용하는 것도 전혀 문제없습니다.
속도
DuckDB 자체와 마찬가지로, DuckLake 역시 속도에 중점을 둡니다. Iceberg와 Delta Lake의 가장 큰 문제점 중 하나는 아주 간단한 쿼리 하나를 실행하는 데도 복잡한 파일 I/O 과정이 필요하다는 점입니다. 카탈로그와 파일 메타데이터 경로를 따라가려면 수많은 개별적인 순차적 HTTP 요청이 필요합니다. 그 결과, 읽기 작업이나 트랜잭션이 실행될 수 있는 속도에 하한선이 존재하게 됩니다. 트랜잭션 커밋의 핵심 경로에서 많은 시간이 소요되어 빈번한 충돌이 발생하고, 이를 해결하는 데 많은 비용이 듭니다. 캐싱을 통해 이러한 문제 중 일부를 완화할 수는 있지만, 이는 복잡성을 가중시킬 뿐이며 '핫' 데이터에만 효과적입니다.
SQL 데이터베이스 내의 통합 메타데이터는 저지연 쿼리 계획 수립도 가능하게 합니다. DuckLake 테이블에서 데이터를 읽기 위해서는 카탈로그 데이터베이스로 단일 쿼리가 전송되며, 카탈로그 데이터베이스는 스키마 기반, 파티션 기반 및 통계 기반 프루닝을 수행하여 BLOB 스토리지에서 읽을 파일 목록을 추출합니다. 메타데이터 상태를 가져오고 재구성하기 위해 스토리지로 여러 번 왕복할 필요가 없습니다. 또한 오류 발생 가능성이 줄어들며, S3 스로틀링, 요청 실패, 재시도, 파일이 보이지 않게 만드는 스토리지의 일관성 미확보 상태 등의 문제가 발생하지 않습니다.
DuckLake는 또한 데이터 레이크의 두 가지 가장 큰 성능 문제, 즉 사소한 변경 사항과 다량의 동시 변경 사항을 개선할 수 있습니다.
사소한 변경 사항의 경우, DuckLake는 스토리지에 기록되는 작은 파일의 수를 획기적으로 줄여줍니다. 이전 버전과 비교해 미미한 변경만 있는 새로운 스냅샷 파일도, 새로운 매니페스트 파일이나 매니페스트 목록도 생성되지 않습니다. DuckLake는 심지어 선택적으로 사소한 변경 사항을 메타데이터 저장소의 실제 테이블에 직접 투명하게 인라인 처리할 수도 있습니다! 결과적으로, 데이터베이스 시스템은 데이터 관리에도 활용될 수 있습니다. 이를 통해 서브 밀리초 단위의 쓰기 성능을 달성할 수 있으며, 읽어야 할 파일 수를 줄임으로써 전반적인 쿼리 성능도 향상됩니다. 작성되는 파일 수가 대폭 감소함에 따라, DuckLake는 정리 및 압축 작업도 크게 간소화합니다.
DuckLake에서 테이블 변경 작업은 두 단계로 이루어집니다. 먼저 데이터 파일(있는 경우)을 스토리지에 스테이징하고, 그 다음 카탈로그 데이터베이스에서 단일 SQL 트랜잭션을 실행하는 것입니다. 이렇게 하면 트랜잭션 커밋의 중요 경로에서 소요되는 시간이 크게 단축되는데, 실행해야 할 트랜잭션이 단 하나뿐이기 때문입니다. SQL 데이터베이스는 트랜잭션 간 충돌을 해결하는 데 매우 능숙합니다. 이는 컴퓨트 노드가 충돌이 발생할 수 있는 핵심 경로에서 소요하는 시간이 훨씬 줄어든다는 것을 의미합니다. 덕분에 충돌 해결 속도가 훨씬 빨라지고, 훨씬 더 많은 트랜잭션을 동시에 처리할 수 있습니다. 본질적으로 DuckLake는 카탈로그 데이터베이스가 커밋할 수 있는 만큼의 테이블 변경을 지원합니다. 유서 깊은 Postgres조차도 초당 수천 건의 트랜잭션을 처리할 수 있습니다. 1초 간격으로 테이블에 데이터를 추가하는 작업을 수행하는 1,000개의 컴퓨트 노드를 가동하더라도 아무 문제없이 작동할 것입니다.
또한, DuckLake의 스냅샷은 메타데이터 저장소에 몇 개의 행만 추가되는 형태이므로, 수많은 스냅샷을 동시에 유지할 수 있습니다. 따라서 스냅샷을 사전에 정리할 필요가 없습니다. 또한 스냅샷은 Parquet 파일의 일부를 참조할 수 있으므로, 디스크에 있는 파일 수보다 훨씬 더 많은 스냅샷을 생성할 수 있습니다. 이러한 기능들이 결합되어 DuckLake는 수백만 개의 스냅샷을 관리할 수 있습니다!
주요 특징
DuckLake에는 여러분이 좋아하는 Lakehouse의 모든 특징이 갖춰져 있습니다:
- 임의의 SQL: DuckLake는 DuckDB 등이 지원하는 것과 동일한 방대한 SQL 기능을 모두 지원합니다.
- 데이터 변경: DuckLake는 데이터에 대한 효율적인 추가, 업데이트 및 삭제를 지원합니다.
- 다중 스키마, 다중 테이블: DuckLake는 동일한 메타데이터 테이블 구조 내에서 각각 임의의 수의 테이블을 포함하는 임의의 수의 스키마를 관리할 수 있습니다.
- 다중 테이블 트랜잭션: DuckLake는 관리되는 모든 스키마, 테이블 및 그 내용에 대해 완전한 ACID 준수를 지원하는 트랜잭션을 제공합니다.
- 복합 데이터형: DuckLake는 목록과 같이 임의로 중첩된 모든 복합 데이터형을 지원합니다.
- 완전한 스키마 진화: 테이블 스키마는 임의로 변경할 수 있으며, 예를 들어 열을 추가하거나 제거하거나 데이터형을 변경할 수 있습니다.
- 스키마 수준 타임 트래블 및 롤백: DuckLake는 완전한 스냅샷 격리 및 타임 트래블을 지원하여 특정 시점의 테이블을 쿼리할 수 있습니다.
- 증분 스캔: DuckLake는 지정된 스냅샷 사이에서 발생한 변경 사항만 검색할 수 있도록 지원합니다.
- SQL 뷰: DuckLake는 지연 평가되는 SQL 수준 뷰의 정의를 지원합니다.
- 숨겨진 파티셔닝 및 프루닝: DuckLake는 데이터 파티셔닝과 테이블 및 파일 수준 통계를 인식하여, 효율성을 극대화하기 위해 스캔을 조기에 프루닝할 수 있습니다.
- 트랜잭션 기반 DDL: 스키마, 테이블 및 뷰의 생성, 변경, 삭제는 완전히 트랜잭션 방식으로 처리됩니다.
- 데이터 압축 최소화: DuckLake는 유사한 포맷에 비해 훨씬 적은 압축 작업만 필요합니다. DuckLake는 스냅샷의 효율적인 압축을 지원합니다.
- 인라인 처리: 데이터에 작은 변경 사항이 있을 때, DuckLake는 선택적으로 카탈로그 데이터베이스를 사용하여 이러한 작은 변경 사항을 직접 저장함으로써 수많은 작은 파일을 생성하는 것을 피할 수 있습니다.
- 암호화: DuckLake는 선택적으로 데이터 저장소에 기록되는 모든 데이터 파일을 암호화하여 제로 트러스트(Zero-Trust) 데이터 호스팅을 가능하게 합니다. 키는 카탈로그 데이터베이스에서 관리됩니다.
- 호환성: DuckLake가 스토리지에 기록하는 데이터 및 (위치 기반) 삭제 파일은 Apache Iceberg와 완벽하게 호환되어 메타데이터만 사용하여 마이그레이션할 수 있습니다.
'EPL과 유튜브 데이터로 배우는 DuckDB' 카테고리의 다른 글
| DuckDB Tricks – Part 2 (0) | 2026.05.17 |
|---|---|
| DuckDB Tricks - Part 1 (0) | 2026.05.17 |
| 2026년의 파이썬 데이터 분석 스택: DuckDB, Polars, 그리고 Pandas의 종말? (0) | 2026.05.15 |
| 모든 데이터 엔지니어가 더 이상 믿어서는 안 될 DuckDB 성능에 관한 7가지 오해 (0) | 2026.05.15 |
| Pandas 사용자의 DuckDB 마스터하기 -Part 1 (0) | 2026.05.15 |
댓글