SeaweedFS 카탈로그
SeaweedFS 카탈로그 (SeaweedFS catalog)
S3 호환 게이트웨이와 내장 Iceberg REST 카탈로그를 가진 SeaweedFS를 ClickHouse에 연결해 Iceberg 테이블을 조회하고 쓰는 방법을 살펴봐요.
출처: 문서
본문
SeaweedFS 카탈로그와의 통합은 Iceberg 테이블에서만 동작해요.
ClickHouse는 여러 카탈로그(Unity, Glue, REST, Polaris 등)와의 통합을 지원해요. 이 가이드에서는 ClickHouse와 SeaweedFS 카탈로그를 사용해 데이터를 조회하는 단계를 안내할게요. SeaweedFS는 S3 호환 게이트웨이가 있는 오픈소스 분산 파일·오브젝트 스토어예요. S3 Table Buckets는 Iceberg 배포의 양쪽 모두를 제공해요. 내장 Iceberg REST 카탈로그가 테이블 메타데이터를 제공하고, 테이블 버킷은 같은 S3 엔드포인트 뒤에 Parquet 파일로 테이블 데이터를 저장해요:
- 단일 서비스 - 카탈로그 메타데이터와 Parquet 데이터를 하나의 프로세스가 제공하며, 별도의 메타데이터 데이터베이스가 없어요
- Iceberg REST 카탈로그 스펙을 준수하는 REST API
- 서버 측 유지보수 - 외부 유지보수 서비스 없이 자동 Parquet 압축과 스냅샷 만료
이 기능은 실험적이므로 SET allow_experimental_database_iceberg = 1;을 사용해 활성화해야 해요.
로컬 개발 설정
로컬 개발과 테스트를 위해 SeaweedFS와 ClickHouse를 Docker Compose로 실행할 수 있어요. 이 접근 방식은 학습, 프로토타이핑, 개발 환경에 이상적이에요.
사전 조건
- Docker와 Docker Compose: Docker가 설치되어 실행 중인지 확인해요
- 버전: SeaweedFS 4.42 이상; ClickHouse 26.8 이상(25.8까지는 읽고 삽입할 수 있지만 카탈로그를 통한 테이블 생성은 26.8 필요)
- PyIceberg가 있는 Python(선택): 아래에서 샘플 데이터를 시딩하는 데 사용
로컬 SeaweedFS 카탈로그 설정하기
Step 1: 예시를 실행할 새 폴더를 만들고 S3 게이트웨이와 카탈로그의 자격 증명으로 파일 s3config.json을 만들어요:
{
"identities": [
{
"name": "analyst",
"credentials": [
{
"accessKey": "tutorialkey",
"secretKey": "tutorialsecret"
}
],
"actions": ["Admin", "Read", "Write", "List", "Tagging"]
}
]
}
Step 2: 다음 구성을 가진 파일 docker-compose.yml을 만들어요:
services:
seaweedfs:
image: chrislusf/seaweedfs:latest
command: mini -dir=/data -s3.config=/etc/seaweedfs/s3config.json -tableBucket=analytics -admin.port=12646
ports:
- "8333:8333" # S3 endpoint
- "8181:8181" # Iceberg REST catalog
volumes:
- ./s3config.json:/etc/seaweedfs/s3config.json
- seaweedfs_data:/data
networks:
- iceberg_net
clickhouse:
image: clickhouse/clickhouse-server:latest
container_name: seaweedfs-clickhouse
ports:
- "8123:8123"
- "9000:9000"
depends_on:
- seaweedfs
networks:
- iceberg_net
volumes:
seaweedfs_data:
networks:
iceberg_net:
driver: bridge
mini 명령은 전체 SeaweedFS 스택을 단일 컨테이너에서 시작해요. -tableBucket=analytics 플래그는 Iceberg 웨어하우스 역할을 하는 analytics라는 S3 Tables 버킷을 미리 생성해요. -admin.port=12646은 SeaweedFS가 여기서 파생하는 admin gRPC 포트를 Linux 임시(ephemeral) 포트 범위 아래에 유지해, 시작 연결이 먼저 차지할 수 있는 상황을 방지해요.
Step 3: 다음 명령을 실행해 서비스를 시작해요:
docker compose up -d
샘플 데이터 시딩하기
카탈로그는 빈 상태로 시작해요. PyIceberg로(pip install pyiceberg pyarrow) 테이블을 만들고 몇 행을 추가해요:
import pyarrow as pa
from pyiceberg.catalog.rest import RestCatalog
catalog = RestCatalog(
"seaweedfs",
uri="http://localhost:8181",
warehouse="s3://analytics",
credential="tutorialkey:tutorialsecret",
**{
"s3.endpoint": "http://localhost:8333",
"s3.access-key-id": "tutorialkey",
"s3.secret-access-key": "tutorialsecret",
"s3.region": "us-east-1",
"s3.path-style-access": "true",
},
)
rows = pa.table({
"id": pa.array([1, 2, 3, 4, 5, 6], pa.int64()),
"region": ["NA", "EU", "EU", "APAC", "NA", "EU"],
"amount": pa.array([12.5, 40.0, 7.25, 99.9, 3.5, 61.0], pa.float64()),
})
catalog.create_namespace("sales")
table = catalog.create_table("sales.orders", schema=rows.schema)
table.append(rows)
로컬 SeaweedFS 카탈로그에 연결하기
ClickHouse 컨테이너에 연결해요:
docker exec -it seaweedfs-clickhouse clickhouse-client
그런 다음 SeaweedFS 카탈로그에 대한 데이터베이스 연결을 만들어요:
SET allow_experimental_database_iceberg = 1;
CREATE DATABASE lake
ENGINE = DataLakeCatalog('http://seaweedfs:8181/v1', 'tutorialkey', 'tutorialsecret')
SETTINGS catalog_type = 'rest',
warehouse = 's3://analytics',
storage_endpoint = 'http://seaweedfs:8333/analytics',
catalog_credential = 'tutorialkey:tutorialsecret',
oauth_server_uri = 'http://seaweedfs:8181/v1/oauth/tokens'
엔진 인자는 ClickHouse가 테이블 데이터를 읽을 때 사용하는 S3 자격 증명을 전달하고, catalog_credential과 oauth_server_uri는 OAuth2 client-credentials 흐름을 통해 카탈로그 자체에 인증해요. SeaweedFS는 둘 다에 같은 액세스 키와 시크릿 키를 받아요.
ClickHouse로 SeaweedFS 카탈로그 테이블 조회하기
이제 연결이 있으니 SeaweedFS 카탈로그를 통해 조회할 수 있어요. 예를 들어:
USE lake;
SHOW TABLES;
┌─name─────────┐
│ sales.orders │
└──────────────┘
백틱 필요 ClickHouse는 네임스페이스를 하나 이상 지원하지 않기 때문에 백틱이 필요해요.
테이블을 조회하려면:
SELECT region, sum(amount) AS total
FROM `sales.orders`
GROUP BY region
ORDER BY total DESC;
┌─region─┬──total─┐
│ EU │ 108.25 │
│ APAC │ 99.9 │
│ NA │ 16 │
└────────┴────────┘
ClickHouse에서 테이블 만들고 데이터 쓰기
ClickHouse에서 직접 SeaweedFS 카탈로그에 테이블을 만들고 쓸 수도 있어요:
SET allow_experimental_database_iceberg = 1;
SET allow_experimental_insert_into_iceberg = 1;
SET write_full_path_in_iceberg_metadata = 1;
CREATE TABLE lake.`sales.returns` (id Int64, reason String)
ENGINE = IcebergS3('http://seaweedfs:8333/analytics/sales/returns/', 'tutorialkey', 'tutorialsecret');
INSERT INTO lake.`sales.returns` VALUES (1, 'damaged'), (2, 'wrong size');
SELECT * FROM lake.`sales.returns` ORDER BY id;
┌─id─┬─reason─────┐
│ 1 │ damaged │
│ 2 │ wrong size │
└────┴────────────┘
IcebergS3 엔진 절은 새 테이블의 스토리지 경로를 지정하고, write_full_path_in_iceberg_metadata는 ClickHouse가 카탈로그에 전체 테이블 위치를 등록하게 해요.
카탈로그를 통한 테이블 생성에는 ClickHouse 26.8 이상이 필요해요. 버전 26.4~26.7은 네임스페이스를 등록하기 전에 테이블 파일을 쓰는데, 네임스페이스가 카탈로그에 이미 존재하지 않으면 SeaweedFS가 이를 거부해요. 26.4 이전 버전은 성공하는 것처럼 보이지만 테이블 파일이 카탈로그에 등록되지 않은 채 오브젝트 스토리지에 쓰여요.
ClickHouse가 삽입을 커밋하면 SeaweedFS 카탈로그가 실험적 writer가 아직 생성하지 않는 메타데이터를 복구해요. 매니페스트의 누락된 필드 ID를 채우고, 버킷 상대 파일 경로를 절대 위치로 다시 쓰고, 테이블에 기본 이름 매핑을 스탬프 처리해요. 그러면 PyIceberg, Spark 같은 엄격한 리더가 ClickHouse가 쓴 행을 읽을 수 있어요. 이는 SeaweedFS 4.42 이상이 필요해요.
데이터 레이크에서 ClickHouse로 데이터 로드하기
SeaweedFS 카탈로그에서 ClickHouse로 데이터를 로드해야 한다면 먼저 로컬 ClickHouse 테이블을 만들어요:
CREATE TABLE default.orders
(
`id` Int64,
`region` String,
`amount` Float64
)
ENGINE = MergeTree()
ORDER BY (region, id);
그런 다음 INSERT INTO SELECT로 SeaweedFS 카탈로그 테이블에서 데이터를 로드해요:
INSERT INTO default.orders
SELECT * FROM lake.`sales.orders`;