본문으로 건너뛰기
clickhouse검색
수집과 통합

오브젝트 스토리지와 데이터 레이크 (s3 함수, Iceberg, Delta Lake, 카탈로그)

S3, GCS, Azure Blob 의 파일을 테이블처럼 읽고 쓰는 s3 계열 함수와 엔진, S3Queue 스트리밍 적재, Iceberg 와 Delta Lake 테이블을 카탈로그째로 붙이는 DataLakeCatalog, 그리고 비용과 성능을 좌우하는 설정을 정리합니다.

S3데이터 레이크IcebergDelta LakeGlueUnity CatalogS3Queue2026-10 기준, 약 14분상태 표시 설명

오브젝트 스토리지를 다루는 네 가지 방식

ClickHouse 는 오브젝트 스토리지를 네 가지 역할로 씁니다. 역할이 다르면 쓰는 문법도 다르니 먼저 구분해 둡니다.

역할문법설명
외부 파일을 쿼리s3(), gcs(), azureBlobStorage(), url(), hdfs() 테이블 함수적재 없이 파일을 바로 읽음. 탐색, 일회성 적재, 내보내기
파일 묶음을 테이블로 고정S3, AzureBlobStorage 테이블 엔진경로와 포맷을 테이블 정의로 저장. 읽기와 쓰기 모두
버킷에 떨어지는 파일을 계속 적재S3Queue, AzureQueue 엔진 + 머티리얼라이즈드 뷰새 파일을 감지해 한 번씩 처리하는 스트리밍 적재
MergeTree 데이터를 오브젝트 스토리지에 저장스토리지 정책의 s3 디스크, ClickHouse Cloud 의 SharedMergeTree테이블 자체의 저장 매체. TTL, 디스크 티어링 과 ClickHouse Cloud 개요 에서 다룸

이 문서는 앞의 세 가지와 레이크 포맷(Iceberg, Delta Lake) 을 다룹니다.

s3 테이블 함수

SELECT count(), min(ts), max(ts)
FROM s3('https://my-bucket.s3.ap-northeast-2.amazonaws.com/events/2026/10/*.parquet', Parquet);

-- 자격 증명 직접, 구조 지정, 압축 명시
SELECT * FROM s3('https://my-bucket.s3.amazonaws.com/raw/day={01..31}/*.json.gz',
                 'AKIA...', 'secret', JSONEachRow,
                 'ts DateTime, user_id UInt64, event String', 'gzip')
LIMIT 10;
  • 경로 패턴 *(한 단계 임의 문자열), **(하위 디렉터리 재귀), ?, {a,b}, {1..31} 을 씁니다. 숫자 범위는 자릿수 패딩도 맞춰 줍니다({01..31}).
  • 가상 컬럼 _path, _file, _size, _time, _etag 로 어느 파일에서 온 행인지 알 수 있습니다. 파일 단위 멱등 적재의 핵심 재료입니다.
  • Hive 파티션 경로 year=2026/month=10/ 같은 경로는 use_hive_partitioning = 1 이면 year, month 가 가상 컬럼으로 잡히고, 그 컬럼의 WHERE 조건은 파일 목록 단계에서 걸러집니다.
  • 포맷과 압축 생략 하면 확장자로 추론합니다. 구조도 생략하면 스키마 추론 이 동작합니다.
  • 클러스터 병렬 s3Cluster('cluster', ...) 는 파일 목록을 노드에 나눠 읽습니다. 25.3 부터는 병렬 복제본(enable_parallel_replicas) 이 켜진 클러스터에서 그냥 s3() 만 써도 자동으로 분산되며, 끄려면 parallel_replicas_for_cluster_engines = 0 을 줍니다.

자격 증명은 named collection 으로

키를 쿼리에 박으면 system.query_log 에 그대로 남습니다. named collection 에 담고 이름으로 부르세요.

CREATE NAMED COLLECTION lake_prod AS
  url = 'https://my-bucket.s3.ap-northeast-2.amazonaws.com/',
  access_key_id = 'AKIA...', secret_access_key = '...';

SELECT count() FROM s3(lake_prod, filename = 'events/2026/10/*.parquet', format = 'Parquet');

EC2 나 EKS 위에서는 키 없이 인스턴스 역할을 쓸 수 있습니다(서버 설정 <s3><use_environment_credentials>true</use_environment_credentials></s3>). 25.8 부터는 extra_credentials(role_arn = 'arn:aws:iam::...:role/reader') 로 쿼리마다 다른 IAM 역할을 맡을 수 있고, GRANT READ ON S3('https://my-bucket/path/*') 처럼 URL 패턴 단위로 권한을 줄 수 있습니다. ClickHouse Cloud 는 서비스마다 IAM 역할 ARN 을 발급해 주므로 버킷 정책에 그 ARN 만 허용하면 됩니다.

쓰기와 내보내기

-- 쿼리 결과를 파일 하나로
INSERT INTO FUNCTION s3(lake_prod, filename = 'export/top_users.parquet', format = 'Parquet')
SELECT user_id, count() AS c FROM events GROUP BY user_id ORDER BY c DESC LIMIT 1000000;

-- Hive 스타일 파티션 디렉터리로 (25.8 부터 S3 엔진의 partition_strategy = 'hive')
CREATE TABLE events_export (ts DateTime, user_id UInt64, event String, dt Date)
ENGINE = S3(lake_prod, filename = 'events_export/', format = 'Parquet', partition_strategy = 'hive')
PARTITION BY dt;
INSERT INTO events_export SELECT ts, user_id, event, toDate(ts) FROM events;

같은 파일 이름에 두 번 INSERT 하면 기본으로는 오류가 납니다. s3_truncate_on_insert = 1 이면 덮어쓰고, s3_create_new_file_on_insert = 1 이면 뒤에 번호를 붙여 새 파일을 만듭니다.

S3Queue: 버킷에 떨어지는 파일을 스트리밍으로

업스트림이 파일을 S3 에 계속 떨어뜨리는 구조(배치 ETL 결과, 로그 수집기, 파트너 전송) 라면 S3Queue 엔진이 "새 파일 감지, 한 번만 처리" 를 맡습니다. 처리한 파일 목록은 Keeper 에 남아 서버가 재시작해도 이어집니다.

CREATE TABLE raw_files_queue (ts DateTime, user_id UInt64, event String)
ENGINE = S3Queue(lake_prod, filename = 'incoming/*.json.gz', format = 'JSONEachRow')
SETTINGS mode = 'unordered',
         keeper_path = '/clickhouse/s3queue/raw_files',
         s3queue_processing_threads_num = 4,
         s3queue_tracked_files_limit = 100000,
         s3queue_polling_min_timeout_ms = 10000;

CREATE MATERIALIZED VIEW raw_files_mv TO events AS
SELECT ts, user_id, event FROM raw_files_queue;
  • mode = 'ordered' 는 파일 이름이 사전순으로 증가한다는 가정 아래 마지막 처리 파일만 기억해 Keeper 부담이 적고, unordered 는 파일마다 기록해 임의 순서를 허용합니다.
  • 처리 결과를 system.s3queue_log 에서 보고, 실패한 파일은 s3queue_loading_retries 만큼 재시도합니다.
  • 25.12 부터는 처리가 끝난 파일을 다른 접두어로 옮기거나 태그를 붙이는 후처리 옵션이 들어와, "처리됨" 폴더 운영이 ClickHouse 안에서 끝납니다.
  • Azure 는 AzureQueue 엔진이 같은 역할입니다. ClickHouse Cloud 에서는 같은 일을 ClickPipes 의 S3, GCS 커넥터(계속 수집 모드) 가 관리형으로 해 줍니다.

팁 S3Queue 는 "파일" 단위 at-least-once 입니다. 처리 도중 서버가 죽으면 파일을 다시 읽을 수 있으니, 저장 테이블 쪽 블록 중복 제거나 _file 기반 중복 제거 설계를 함께 두세요.

Iceberg

Iceberg 테이블은 테이블 함수로 바로 읽을 수도 있고, 카탈로그를 데이터베이스로 붙여 여러 테이블을 한 번에 볼 수도 있습니다.

-- 메타데이터 위치만 알면 바로
SELECT count() FROM iceberg('https://bucket.s3.amazonaws.com/warehouse/db/orders/', lake_prod);

-- 과거 스냅샷 (25.4 부터 time travel)
SELECT count() FROM iceberg(...) SETTINGS iceberg_timestamp_ms = 1759276800000;
SELECT count() FROM iceberg(...) SETTINGS iceberg_snapshot_id = 5839234231;

-- 스냅샷 이력
SELECT * FROM system.iceberg_history WHERE table = 'orders';

DataLakeCatalog 데이터베이스 엔진 은 카탈로그에 등록된 테이블을 ClickHouse 데이터베이스처럼 보여 줍니다. 25.3 에 AWS Glue 와 Unity Catalog, 25.5 에 Hive Metastore 가 들어왔고, 25.8 에 REST, Glue, Unity, Hive Metastore 카탈로그가 Beta 로 올라갔습니다.

CREATE DATABASE lake ENGINE = DataLakeCatalog('https://glue.ap-northeast-2.amazonaws.com')
SETTINGS catalog_type = 'glue', region = 'ap-northeast-2',
         aws_access_key_id = '...', aws_secret_access_key = '...';

SHOW TABLES FROM lake;
SELECT * FROM lake.`sales.orders` LIMIT 10;   -- 네임스페이스.테이블 을 백틱으로
  • 읽기는 파티션 가지치기, 매니페스트 기반 파일 건너뛰기, positional 과 equality delete 파일 적용, 스키마 진화를 지원합니다. 메타데이터 캐시(use_iceberg_metadata_files_cache) 가 반복 쿼리를 빠르게 합니다.
  • 쓰기(INSERT, DELETE, UPDATE, 스키마 변경) 는 25.8 에 IcebergS3 엔진으로 들어왔지만 Exp 입니다. REST 와 Glue 카탈로그를 통한 쓰기도 같은 단계입니다. 운영 적재의 기준 복사본을 Iceberg 로 쓸 계획이라면 버전별 상태를 꼭 확인하세요.
  • 2026년 들어 S3 Tables 와 Horizon 같은 새 카탈로그가 추가됐습니다. 2026년 주요 변화 에 정리했습니다.

Delta Lake 와 Hudi

SELECT count() FROM deltaLake('https://bucket.s3.amazonaws.com/warehouse/db/orders/', lake_prod);
  • 25.2 에 Databricks 의 Rust 커널(delta-kernel-rs) 기반 새 구현이 Exp 로 들어왔고(allow_experimental_delta_kernel_rs), 이후 기본 경로가 됐습니다. Deletion vector, 컬럼 매핑 같은 최신 프로토콜 기능을 이 커널이 처리합니다.
  • 25.8 부터 Delta Lake 쓰기와 time travel, 25.12 부터 변경 데이터 피드(CDF) 읽기가 들어왔습니다. Unity Catalog 를 DataLakeCatalog 로 붙이면 Delta 와 Iceberg 테이블을 함께 봅니다.
  • Hudi 는 hudi() 함수로 읽기만 지원합니다.

레이크 쿼리를 빠르게

설정 또는 방법효과
Parquet 필터 푸시다운, Bloom 필터, 리더 v3읽을 행 그룹과 페이지를 줄임. 입출력 포맷 참고
use_hive_partitioning, Iceberg 파티션 가지치기파일 목록 단계에서 제외
병렬 복제본 또는 s3Cluster파일을 노드에 나눠 읽음
max_download_threads, max_download_buffer_size파일 하나를 조각내 병렬 다운로드
enable_filesystem_cache(캐시 디스크 구성 필요)자주 읽는 원격 파일 조각을 로컬에 캐시
schema_inference_use_cache_for_s3반복 쿼리의 스키마 추론 비용 제거
자주 쓰는 데이터는 MergeTree 로 복사레이크 직접 쿼리는 탐색용, 대시보드는 적재 후

레이크 직접 쿼리는 편하지만 MergeTree 보다 몇 배에서 수십 배 느립니다. 반복해서 보는 데이터는 INSERT INTO ... SELECT FROM s3(...) 로 적재하고, 레이크는 원본 보관과 다른 엔진과의 공유에 쓰는 구성이 가장 흔합니다.

비용에서 놓치기 쉬운 것

  • LIST 요청 넓은 글롭(**) 은 파일 목록을 전부 받아 옵니다. 파일이 수백만 개면 목록만으로 수십 초와 요청 비용이 듭니다. 경로를 날짜까지 좁히세요.
  • GET 요청 파일이 작을수록 행당 요청 수가 늘어납니다. 레이크 쪽에서 파일을 100 MB 안팎으로 합치는 것이 ClickHouse 설정보다 효과가 큽니다.
  • 리전 간 전송 버킷과 ClickHouse 가 다른 리전이면 전송 요금이 붙습니다. ClickHouse Cloud 서비스는 버킷과 같은 리전에 만드세요.
  • 스키마 추론 재실행 캐시가 꺼져 있으면 같은 경로를 쿼리할 때마다 파일 앞부분을 다시 읽습니다.

공식 문서

이 문서에서