Learning Platform
Глоссарий Troubleshooting
Урок 11.02 · 23 мин
Средний
httpfss3secretsobject-storage

httpfs: чтение S3, GCS, Azure и HTTP

В прошлых уроках мы читали файлы с локального диска. Но в реальной аналитике данные живут в объектном хранилище — S3, Google Cloud Storage, Azure Blob. Расширение httpfs стирает эту границу: после его подключения путь s3://bucket/data/file.parquet работает в read_parquet ровно так же, как локальный путь. Все оптимизации предыдущего модуля — projection pushdown, filter pushdown, partition pruning, glob-шаблоны — продолжают действовать поверх объектного хранилища. Этот урок про то, как httpfs устроен и как безопасно передать ему учётные данные через механизм secrets.

httpfs как виртуальная файловая система

Trino: Lakehouse-архитектура и object storage

Ключевая идея httpfs: он регистрирует в DuckDB новые файловые системы. Ядро DuckDB работает с файлами через абстракцию file system — у неё есть операции «открыть», «прочитать диапазон байт», «узнать размер». Локальная файловая система — одна реализация этой абстракции. httpfs добавляет ещё несколько: для протокола s3://, для gcs://, для azure:// (азурную часть фактически обслуживает расширение azure, тесно связанное с httpfs), для http:// и https://.

Сканер Parquet не знает и не должен знать, откуда берутся байты. Он просит файловую систему «дай мне байты с 1000 по 5000» — а уж локальная это файловая система или S3-реализация httpfs, делающая HTTP-запрос с заголовком Range, ему безразлично. Поэтому весь механизм pushdown работает поверх S3 без изменений: DuckDB по footer вычисляет нужные байтовые диапазоны и запрашивает только их HTTP Range-запросами.

httpfs регистрирует файловые системы для удалённых протоколов
read_parquet('s3://...')Сканер запрашивает байтовые диапазоны через абстракцию файловой системы, не зная, что источник удалённый
запрос диапазона
S3-файловая система httpfsРеализация file system от httpfs: переводит запрос диапазона в HTTP-запрос с заголовком Range
HTTP Range
Объектное хранилищеS3, GCS или совместимое хранилище возвращает только запрошенный кусок файла

httpfs — core-расширение и autoloadable: первое обращение к s3://-пути подтянет его само. Явный INSTALL httpfs; LOAD httpfs; нужен редко, но знать про него полезно для офлайн-окружений.

-- httpfs подтянется автоматически при обращении к s3://
SELECT COUNT(*) FROM 's3://my-bucket/events/2026/*.parquet';

-- Чтение публичного файла прямо по HTTP — тоже httpfs
SELECT * FROM read_csv('https://example.com/data.csv') LIMIT 5;

Range-запросы: почему чтение с S3 не так дорого, как кажется

Может показаться, что запрос к 10-гигабайтному Parquet на S3 обязан скачать все 10 ГБ. Это не так — и причина в том, что HTTP поддерживает заголовок Range, позволяющий запросить произвольный кусок файла, а не файл целиком.

DuckDB этим активно пользуется. Чтение Parquet с S3 идёт по шагам: сначала маленький Range-запрос на footer (метаданные в конце файла), из footer DuckDB узнаёт схему, расположение row groups и их статистику; затем — projection pushdown отбрасывает ненужные колонки, filter pushdown по статистике отбрасывает ненужные row groups; и только потом DuckDB делает Range-запросы ровно на те байтовые диапазоны, где лежат нужные column chunk-и нужных row groups. Из 10 ГБ по сети может реально прийти несколько сотен мегабайт.

Поэтому правило из модуля про внешние данные на S3 действует с удвоенной силой: не пишите SELECT *, фильтруйте по кластеризованным колонкам. На локальном диске лишнее чтение стоит времени; на S3 оно стоит времени, трафика и денег за исходящий трафик.

TIP

CSV и JSON на S3 в этом смысле хуже Parquet. У них нет footer, и filter pushdown по row groups невозможен — чтобы что-то посчитать, файл приходится во многом прочитать целиком по сети. Если данные большие и лежат в облаке, держите их в Parquet, а не в CSV: разница в объёме скачиваемого по сети будет в разы.

Проблема учётных данных

Приватный бакет требует аутентификации: ключ доступа и секретный ключ для AWS, ключ аккаунта для Azure, и так далее. Возникает вопрос — как передать эти данные DuckDB безопасно. Соблазнительный, но плохой путь — вписать ключи прямо в текст запроса или в конфигурацию. Тогда секреты утекут в логи запросов, в историю команд, в текст сохранённого SQL-файла. Это типичная утечка учётных данных.

DuckDB решает проблему механизмом secrets — отдельным защищённым хранилищем учётных данных внутри DuckDB. Вы один раз создаёте secret, а в запросах ключи больше не упоминаете вообще: при обращении к s3:// DuckDB сам находит подходящий secret и берёт данные из него.

CREATE SECRET: правильный способ

Secret создаётся командой CREATE SECRET. У него есть тип (S3, GCS, AZURE и другие) и провайдер — способ, которым secret получает значения.

Провайдер CONFIG — значения задаются явно в команде:

CREATE SECRET my_s3 (
    TYPE s3,
    KEY_ID 'AKIA...',
    SECRET 'wJalr...',
    REGION 'eu-central-1'
);

Провайдер CREDENTIAL_CHAIN — значения не пишутся вообще; DuckDB берёт их из стандартной цепочки источников AWS: переменные окружения, файл ~/.aws/credentials, IAM-роль EC2-инстанса или контейнера. Это предпочтительный способ в продакшене: в SQL-коде нет ни одного ключа.

-- Никаких ключей в коде: данные берутся из окружения / IAM-роли
CREATE SECRET my_s3 (
    TYPE s3,
    PROVIDER credential_chain
);

После создания secret запросы к s3:// просто работают — ключи в них не нужны:

CREATE SECRET my_s3 (TYPE s3, PROVIDER credential_chain);

-- Secret подхватывается автоматически, в запросе ключей нет
SELECT carrier, COUNT(*) AS n
FROM 's3://my-private-bucket/flights/*.parquet'
GROUP BY carrier;
Secrets: учётные данные отделены от запросов
CREATE SECRET (один раз)Учётные данные сохраняются в защищённом хранилище secrets; провайдер credential_chain вообще не требует писать ключи
запрос к s3://
DuckDB ищет подходящий secretПри обращении к s3://-пути DuckDB по типу и scope находит нужный secret
ключи взяты из secret
Запрос без ключей в текстеSQL-код не содержит ни одного секрета — ничего не утечёт в логи и историю

Scope: несколько secrets для разных хранилищ

В одном проекте часто несколько бакетов в разных аккаунтах или облаках. Чтобы DuckDB понимал, какой secret к какому пути применять, у secret есть scope — префикс пути, на который он распространяется.

-- Secret для конкретного бакета
CREATE SECRET prod_data (
    TYPE s3,
    PROVIDER credential_chain,
    SCOPE 's3://prod-bucket'
);

-- Другой secret для другого бакета
CREATE SECRET analytics_data (
    TYPE s3,
    PROVIDER credential_chain,
    SCOPE 's3://analytics-bucket'
);

При запросе DuckDB выбирает secret с самым длинным совпадающим scope-префиксом. Запрос к s3://prod-bucket/... возьмёт prod_data, к s3://analytics-bucket/...analytics_data. Это та же логика «самое специфичное правило побеждает», что и при выборе таблицы каталогом.

По умолчанию secret временный — живёт только в текущей сессии. CREATE PERSISTENT SECRET сохраняет secret на диск (в зашифрованном виде), и он переживает перезапуск DuckDB. Посмотреть все secrets можно через SELECT * FROM duckdb_secrets() — в выводе сами секретные значения скрыты.

СвойствоВременный secretPERSISTENT SECRET
Где хранитсяВ памяти сессииНа диске (зашифрован)
Переживает перезапускНетДа
Когда применятьРазовые задачи, ноутбукПостоянный пайплайн, сервер
WARNING

S3-совместимых хранилищ много — MinIO, Cloudflare R2, Backblaze B2 — и все они говорят на протоколе S3, но по другому адресу (endpoint). Для них в CREATE SECRET нужно явно задать ENDPOINT и обычно URL_STYLE ‘path’. Без указания endpoint DuckDB по умолчанию обратится к настоящему AWS S3 и получит ошибку аутентификации, которая выглядит загадочно, пока не вспомнишь про endpoint. Параметр USE_SSL управляет тем, идёт ли соединение по HTTPS.

Попробуй сам

Для этого задания удобно поднять локальный MinIO (S3-совместимое хранилище в Docker) — тогда не нужен реальный AWS-аккаунт.

  1. Прочитайте публичный файл по HTTP без всякой настройки: SELECT * FROM read_csv('https://...public.csv') LIMIT 10. Убедитесь, что httpfs подтянулся автоматически — проверьте через duckdb_extensions().
  2. Поднимите MinIO, создайте бакет, положите в него Parquet-файл. Создайте CREATE SECRET типа s3 с провайдером CONFIG, обязательно указав ENDPOINT MinIO и URL_STYLE ‘path’. Прочитайте файл по пути s3://bucket/file.parquet.
  3. Выполните SELECT * FROM duckdb_secrets() и убедитесь, что secret виден, но его секретное значение в выводе скрыто.
  4. Создайте два secrets с разными SCOPE и объясните себе, по какому правилу DuckDB выберет нужный при запросе к конкретному бакету. Сравните временный secret и PERSISTENT SECRET: какой переживёт перезапуск процесса.

Parquet поверх объектного хранилища: HTTP range requests и оптимизации
Проверка знанийKnowledge check
Как расширение httpfs позволяет читать файлы из S3 теми же средствами, что и локальные, и почему механизм secrets безопаснее, чем указание ключей доступа прямо в запросе?
ОтветAnswer
Расширение httpfs регистрирует в DuckDB новые реализации абстракции файловой системы — для протоколов s3://, gcs://, http:// и других. Ядро DuckDB работает с файлами через эту абстракцию: у неё есть операции открыть файл, узнать размер, прочитать диапазон байт. Сканер Parquet не знает и не должен знать, локальный это файл или удалённый — он просто просит файловую систему дать байты с одной позиции по другую. S3-реализация от httpfs переводит такой запрос диапазона в HTTP-запрос с заголовком Range. Благодаря этому все оптимизации работают поверх объектного хранилища без изменений: DuckDB читает footer небольшим Range-запросом, применяет projection и filter pushdown, и скачивает по сети только те байтовые диапазоны, где лежат нужные данные — из десятигигабайтного файла реально может прийти несколько сотен мегабайт. Механизм secrets безопаснее указания ключей прямо в запросе, потому что ключи в тексте запроса утекают в логи запросов, в историю команд и в сохранённые SQL-файлы — это типичная утечка учётных данных. Secret — это отдельное защищённое хранилище учётных данных внутри DuckDB: вы создаёте secret один раз командой CREATE SECRET, а в запросах ключи больше не упоминаете вообще, потому что при обращении к s3://-пути DuckDB сам находит подходящий по типу и scope secret и берёт данные из него. Особенно безопасен провайдер credential_chain — он не требует писать ключи в SQL-код вовсе, а берёт их из переменных окружения, файла ~/.aws/credentials или IAM-роли. У secret есть scope — префикс пути, на который он распространяется, что позволяет держать разные учётные данные для разных бакетов, и PERSISTENT-вариант, который хранится на диске в зашифрованном виде.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 4. Как расширение httpfs позволяет читать s3://-файлы теми же средствами, что и локальные?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 7