S3 API 지원
S3 API 지원
httpfs 확장은 S3 API를 사용해 객체 스토리지 서버의 파일을 읽기·쓰기·글로빙(globbing) 하도록 지원해요. S3는 원격 파일에 읽고 쓰기 위한 표준 API를 제공하는데, S3 이전의 일반 HTTP 서버들은 공통 쓰기 API를 제공하지 않았어요. DuckDB는 이제 업계 스토리지 제공자들 사이에서 표준이 된 S3 API를 따릅니다.
출처: 문서
본문
지원 플랫폼
httpfs 파일시스템은 AWS S3, Minio, Google Cloud, lakeFS에서 테스트됐어요. S3 API를 구현하는 다른 서비스(Cloudflare R2, SeaweedFS, Tigris 등)도 동작해야 하지만, 일부 기능은 지원되지 않을 수 있어요.
다음 표는 각 httpfs 기능에 필요한 S3 API 부분을 보여줍니다.
| 기능 | 필요한 S3 API 기능 |
|---|---|
| 공개 파일 읽기 | HTTP Range 요청 |
| 비공개 파일 읽기 | 시크릿 키 또는 세션 토큰 인증 |
| 파일 글로브 | ListObjectsV2 |
| 파일 쓰기 | Multipart upload |
구성과 인증
S3 엔드포인트를 구성하고 인증하는 권장 방법은 secrets를 사용하는 것이에요. 여러 시크릿 제공자(provider)를 사용할 수 있습니다.
S3 API(레거시 인증 방식)에서 마이그레이션하려면 프로필과 함께 정의된 시크릿을 사용하세요. 자세한 내용은 Selecting a Profile을 참고해 주세요.
config 제공자
기본 제공자인 config(즉, 사용자가 구성하는 방식)는 키를 수동으로 제공해 S3 버킷에 접근할 수 있게 해줘요. 예를 들어 볼게요.
CREATE OR REPLACE SECRET secret (
TYPE s3,
PROVIDER config,
KEY_ID '⟨«redacted:AKIA…»⟩',
SECRET '⟨wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY⟩',
REGION '⟨us-east-1⟩'
);
팁 — IO Error(
Connection error for HTTP HEAD)가 발생하면ENDPOINT 's3.⟨your-region⟩.amazonaws.com'로 엔드포인트를 명시적으로 구성하세요.
이제 위 시크릿을 사용해 쿼리하려면, 그냥 s3:// 프리픽스가 붙은 파일을 쿼리하면 돼요.
SELECT *
FROM 's3://⟨your-bucket⟩/⟨your_file⟩.parquet';
credential_chain 제공자
credential_chain 제공자는 AWS SDK를 사용해 자격 증명(프로필, SSO, assumed role, 웹 아이덴티티, 인스턴스 메타데이터 등)을 자동으로 가져와요. aws 확장이 제공하죠. 예를 들어 AWS SDK 기본 제공자를 사용하려면:
CREATE OR REPLACE SECRET secret (
TYPE s3,
PROVIDER credential_chain
);
credential_chain의 전체 옵션(CHAIN 값, 프로필 선택, role 맡기, SSO, 웹 아이덴티티(IRSA), 리전 결정, 검증, 자동 갱신)은 AWS 확장 페이지를 참고해 주세요.
S3 시크릿 파라미터 개요
다음은 config와 credential_chain 제공자 양쪽에서 사용할 수 있는 지원 파라미터 전체 목록이에요.
| 이름 | 설명 | 시크릿 | 타입 | 기본값 |
|---|---|---|---|---|
ENDPOINT |
사용자 지정 S3 엔드포인트 지정 | S3, GCS, R2 |
STRING |
S3는 s3.amazonaws.com |
KEY_ID |
사용할 키의 ID | S3, GCS, R2 |
STRING |
- |
REGION |
인증할 리전 (질의할 버킷의 리전과 일치해야 함) | S3, GCS, R2 |
STRING |
us-east-1 |
SECRET |
사용할 키의 시크릿 | S3, GCS, R2 |
STRING |
- |
SESSION_TOKEN |
선택적으로 임시 자격 증명을 위해 세션 토큰 전달 | S3, GCS, R2 |
STRING |
- |
URL_COMPATIBILITY_MODE |
URL에 문제가 되는 문자가 있을 때 도움이 됨 | S3, GCS, R2 |
BOOLEAN |
true |
URL_STYLE |
vhost(별칭 virtual) 또는 path |
S3, GCS, R2 |
STRING |
S3는 vhost, R2·GCS는 path |
USE_SSL |
HTTPS를 쓸지 HTTP를 쓸지 | S3, GCS, R2 |
BOOLEAN |
true |
VERIFY_SSL |
서버의 SSL 인증서를 검증할지 | S3, GCS, R2 |
BOOLEAN |
true |
ACCOUNT_ID |
엔드포인트 URL 생성에 사용할 R2 계정 ID | R2 |
STRING |
- |
KMS_KEY_ID |
S3 서버 측 암호화용 AWS KMS 키 | S3 |
STRING |
- |
REQUESTER_PAYS |
"requester pays" S3 버킷 사용 허용 | S3 |
BOOLEAN |
false |
REFRESH |
auto로 설정해 자격 증명을 주기적으로 갱신 (aws 확장 참고) |
S3, GCS, R2 |
STRING |
- |
자동 자격 증명 갱신
REFRESH 시크릿 파라미터와는 별개로, DuckDB는 요청이 HTTP 401 또는 403 상태로 실패하면(예: 임시 자격 증명이 만료된 경우) S3 자격 증명을 자동으로 갱신한 뒤 요청을 재시도해요. 이 동작은 httpfs_enable_credential_refresh 설정(BOOLEAN, 기본값 true)으로 제어됩니다.
SET httpfs_enable_credential_refresh = false;
플랫폼별 시크릿 타입
S3 시크릿
httpfs 확장은 KMS_KEY_ID 옵션으로 S3에서 AWS Key Management Service(KMS)를 통한 서버 측 암호화를 지원해요.
CREATE OR REPLACE SECRET secret (
TYPE s3,
PROVIDER credential_chain,
CHAIN config,
REGION '⟨eu-west-1⟩',
KMS_KEY_ID 'arn:aws:kms:⟨region⟩:⟨account_id⟩:⟨key⟩/⟨key_id⟩',
SCOPE 's3://⟨bucket-sub-path⟩'
);
R2 시크릿
Cloudflare R2는 일반 S3 API를 사용하지만, DuckDB는 구성을 조금 더 간단히 하기 위해 특별한 시크릿 타입 R2를 제공해요.
CREATE OR REPLACE SECRET secret (
TYPE r2,
KEY_ID '⟨«redacted:AKIA…»⟩',
SECRET '⟨wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY⟩',
ACCOUNT_ID '⟨my_account_id⟩'
);
올바른 엔드포인트 URL을 생성해 주는 ACCOUNT_ID가 추가된 점을 주목하세요. 또한 R2 시크릿은 CONFIG와 credential_chain 제공자 양쪽을 사용할 수 있어요. 다만 DuckDB는 내부적으로 AWS 클라이언트를 사용하므로, credential_chain을 쓸 때 클라이언트는 표준 AWS 자격 증명 위치(환경 변수, 자격 증명 파일 등)에서 AWS 자격 증명을 검색해요. 따라서 credential chain이 제대로 동작하려면 R2 자격 증명을 AWS 환경 변수(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)로 제공해야 해요. 마지막으로, R2 시크릿은 r2://로 시작하는 URL을 사용할 때만 쓸 수 있어요.
SELECT *
FROM read_parquet('r2://⟨some-file-that-uses-an-r2-secret⟩.parquet');
GCS 시크릿
Google Cloud Storage는 DuckDB가 S3 API로 접근하지만, 구성을 조금 더 간단히 하기 위해 DuckDB는 특별한 시크릿 타입 GCS를 제공해요.
CREATE OR REPLACE SECRET secret (
TYPE gcs,
KEY_ID '⟨my_hmac_access_id⟩',
SECRET '⟨my_hmac_secret_key⟩'
);
중요: KEY_ID와 SECRET 값은 Google Cloud Storage 상호운용을 위해 특별히 생성된 HMAC 키여야 해요. 이는 일반 GCP 서비스 계정 키나 액세스 토큰과는 달라요. HMAC 키는 Google Cloud의 managing HMAC keys 문서를 따라 만들 수 있습니다.
위 시크릿은 자동으로 올바른 Google Cloud Storage 엔드포인트가 구성돼요. 또한 GCS 시크릿은 CONFIG와 credential_chain 제공자 양쪽을 사용할 수 있어요. 다만 DuckDB는 내부적으로 AWS 클라이언트를 사용하므로, credential_chain을 쓰면 클라이언트는 표준 위치에서 AWS 자격 증명을 검색해요. 따라서 GCS HMAC 키를 AWS_ACCESS_KEY_ID·AWS_SECRET_ACCESS_KEY 환경 변수로 제공해야 credential chain이 동작해요. 마지막으로, GCS 시크릿은 gcs:// 또는 gs://로 시작하는 URL을 사용할 때만 쓸 수 있어요.
SELECT *
FROM read_parquet('gcs://⟨some/file/that/uses/a/gcs/secret⟩.parquet');
읽기
S3에서 파일 읽기는 이제 이렇게 간단해요.
SELECT *
FROM 's3://⟨your-bucket⟩/⟨filename⟩.⟨extension⟩';
부분 읽기
httpfs 확장은 S3 버킷에서의 부분 읽기를 지원해요.
객체 버전 고정
기본적으로 오래 실행되는 쿼리는 읽기 시점에 현재인 버전의 객체를 다시 읽는데, 객체가 덮어써지면 바뀔 수 있어요. s3_version_id_pinning(BOOLEAN, 기본값 false)을 설정하면 첫 HEAD 요청에서 포착한 객체 버전에 읽기를 고정할 수 있어요. 쿼리 중간에 객체가 덮어써도 쿼리가 일관된 버전을 보게 되는 거죠. 이 기능은 HTTP 메타데이터 캐시가 필요해요.
SET enable_http_metadata_cache = true;
SET s3_version_id_pinning = true;
여러 파일 읽기
여러 파일도 가능해요. 예를 들어 볼게요.
SELECT *
FROM read_parquet([
's3://⟨your-bucket⟩/⟨filename-1⟩.parquet',
's3://⟨your-bucket⟩/⟨filename-2⟩.parquet'
]);
글로빙
파일 글로빙은 ListObjectsV2 API 호출로 구현되며, 파일시스템과 같은 글로브 패턴으로 여러 파일을 매칭할 수 있어요.
SELECT *
FROM read_parquet('s3://⟨your-bucket⟩/*.parquet');
이 쿼리는 Parquet 확장을 사용해 버킷 루트의 모든 파일을 매칭해요.
몇 가지 매칭 기능이 지원돼요. *는 임의 개수의 임의 문자, ?는 단일 문자, [0-9]는 문자 범위의 단일 문자를 매칭합니다.
SELECT count(*) FROM read_parquet('s3://⟨your-bucket⟩/folder*/100?/t[0-9].parquet');
글로브를 쓸 때 유용한 기능이 하나 더 있는데요, 바로 filename 옵션이에요. 특정 행이 어느 파일에서 왔는지를 담는 filename 컬럼을 추가해 줍니다.
SELECT *
FROM read_parquet('s3://⟨your-bucket⟩/*.parquet', filename = true);
이렇게 하면 예를 들어 다음과 같은 결과가 나올 수 있어요.
| column_a | column_b | filename |
|---|---|---|
| 1 | examplevalue1 | s3://bucket-name/file1.parquet |
| 2 | examplevalue1 | s3://bucket-name/file2.parquet |
Hive 파티셔닝
DuckDB는 HTTP(S)와 S3 엔드포인트를 사용할 때 이용 가능한 Hive 파티셔닝 스킴도 지원해요.
쓰기
S3에 쓰기는 multipart upload API를 사용해요. 이 덕분에 DuckDB는 고속으로 파일을 안정적으로 업로드할 수 있어요. S3로의 쓰기는 CSV와 Parquet 모두에서 동작합니다.
COPY table_name TO 's3://⟨your-bucket⟩/⟨filename⟩.⟨extension⟩';
S3로의 파티셔닝된 복사도 동작해요.
COPY table TO 's3://⟨your-bucket⟩/partitioned' (
FORMAT parquet,
PARTITION_BY (⟨part_col_a⟩, ⟨part_col_b⟩)
);
기존 파일/디렉토리에 대한 자동 검사가 수행되는데, 현재는 꽤 보수적이에요 (그리고 S3에서는 약간의 지연을 더합니다). 이 검사를 비활성화하고 강제로 쓰려면 OVERWRITE_OR_IGNORE 플래그를 추가하면 돼요.
COPY table TO 's3://⟨your-bucket⟩/partitioned' (
FORMAT parquet,
PARTITION_BY (⟨part_col_a⟩, ⟨part_col_b⟩),
OVERWRITE_OR_IGNORE true
);
쓰여진 파일의 명명 스킴은 이렇게 생겼어요.
s3://⟨your-bucket⟩/partitioned/part_col_a=⟨val⟩/part_col_b=⟨val⟩/data_⟨thread_number⟩.parquet
구성
S3 업로드에는 몇 가지 추가 구성 옵션이 있는데, 대부분의 사용 사례에는 기본값으로 충분해요.
| 이름 | 설명 | 기본값 |
|---|---|---|
s3_uploader_max_parts_per_file |
파트 크기 계산에 사용, AWS 문서 참고 | 10000 |
s3_uploader_max_filesize |
파트 크기 계산에 사용, AWS 문서 참고 | 800GB |
s3_uploader_thread_limit |
업로더 스레드 최대 개수 | 50 |
추가 S3 관련 설정(enable_global_s3_configuration, merge_http_secret_into_s3_request, s3_allow_recursive_globbing, httpfs_enable_credential_refresh, s3_version_id_pinning, unsafe_disable_etag_checks 등)은 구성 레퍼런스에 문서화되어 있습니다.
더 알아보기 (Learn more)
- 시크릿 생성은
sql/statements/create_secret문서를 참고해 주세요. - 레거시 S3 인증 방식은
core_extensions/httpfs/s3api_legacy_authentication문서를 참고해 주세요.