Learning Platform
Глоссарий Troubleshooting
Урок 10.01 · 22 мин
Средний
lakehouseicebergobject-storagetable-format

Lakehouse-архитектура: открытые форматы таблиц поверх object storage

Предыдущие модули разбирали Trino как движок: координатор, воркеры, сплиты, операторы. Этот модуль отвечает на вопрос, ради которого Trino чаще всего и разворачивают в продакшене: как заставить распределённый SQL-движок работать поверх петабайтов файлов в object storage так, будто это обычные таблицы базы данных. Ответ — lakehouse, и его сердце — открытый формат таблиц. В этом уроке разберём, какую конкретную проблему он решает и почему «папка с Parquet-файлами» — это ещё не таблица.

Две архитектуры, между которыми втиснулся lakehouse

Исторически аналитика жила в двух разных мирах. Data warehouse (Snowflake, Teradata, классический Redshift) — это система, которая хранит данные в собственном проприетарном формате, управляет ими через свой движок и даёт строгие гарантии: транзакции, согласованность, статистику, оптимизатор. Цена — данные заперты внутри: чтобы их прочитать, нужен этот конкретный движок, а compute и storage обычно связаны или тарифицируются вместе.

Data lake — противоположность. Это просто object storage (S3, GCS, Azure Blob, HDFS) с файлами в открытых форматах: Parquet, ORC, Avro, CSV. Хранение дёшево, форматы открыты, читать может кто угодно — Spark, Trino, pandas, DuckDB. Но lake не даёт почти никаких гарантий. Нет атомарности: если запись на середине упала, читатель увидит половину файлов. Нет согласованного списка файлов: list object storage возвращает то, что есть прямо сейчас. Нет schema evolution: переименовали колонку — старые файлы об этом не знают. Нет статистики для оптимизатора. Это «болото данных» — данные есть, но доверять им как таблице нельзя.

Warehouse и lake: компромисс, который убирает lakehouse
Data warehouseПроприетарный формат, строгие транзакции и статистика, но данные заперты внутри одного движка, compute и storage связаны
lakehouse берёт лучшее
LakehouseОткрытые файлы Parquet/ORC в object storage плюс слой метаданных формата таблиц, дающий транзакции и статистику
lakehouse берёт лучшее
Data lakeДешёвое object storage и открытые форматы, но без транзакций, без согласованного списка файлов, без schema evolution

Lakehouse — это архитектура, которая берёт хранение и открытость из lake, а гарантии — из warehouse. Файлы данных по-прежнему лежат в object storage в открытом формате (обычно Parquet). Но поверх них добавляется слой метаданных — открытый формат таблиц. Именно он превращает набор файлов в настоящую таблицу с транзакциями, версионированием и статистикой. Trino — один из движков, которые читают и пишут этот слой. Главных открытых форматов таблиц три: Apache Iceberg, Delta Lake и Apache Hudi. Этот модуль и следующий разбирают, как Trino работает с каждым.

Apache Iceberg: каталог и иерархия метаданных Delta Lake: архитектура Transaction Log Spark: архитектура Lakehouse

Почему «папка с Parquet» — это не таблица

Возьмём конкретный сценарий. У вас в S3 лежит s3://lake/orders/ с тысячей Parquet-файлов. Чтобы это была таблица, движку нужно ответить на четыре вопроса, и data lake сам по себе не отвечает ни на один.

Какие файлы входят в таблицу прямо сейчас? Кажется, что ответ — «все, что в папке». Но представьте: идёт запись, заливающая 200 новых файлов. Параллельный SELECT делает list по папке. Он увидит, например, 140 из 200 новых файлов — операция list над object storage не атомарна. Запрос прочитает несогласованный срез данных и не упадёт, просто молча вернёт неверный результат. Это самый коварный класс багов в data lake.

Какая у таблицы схема? Файл Parquet хранит свою схему. Но если за три года колонку добавляли, удаляли и переименовывали, разные файлы имеют разные схемы. Без внешнего описания «вот текущая схема таблицы и как поля каждого файла на неё мапятся» движок не сможет прочитать таблицу целостно.

Как сделать запись атомарной? Запросу нужно добавить 200 файлов и удалить 50 старых. Если между этими шагами читатель сделает list, он увидит несогласованное промежуточное состояние. Нужен механизм, при котором изменение видно либо целиком, либо никак.

Какие файлы можно пропустить? Запрос WHERE order_date = DATE '2026-05-01'. В идеале движок не должен открывать файлы, где таких дат заведомо нет. Для этого нужна статистика — min/max каждой колонки по каждому файлу — заранее, до того как файл будет прочитан.

Что добавляет формат таблиц к набору файлов
Файлы данныхParquet или ORC файлы в object storage — собственно строки таблицы, колоночно сжатые
формат таблиц добавляет слой метаданных
Слой метаданныхМанифесты со списком файлов, схема, партиционирование, статистика min/max, история снапшотов — всё, что делает файлы таблицей
движок видит таблицу
Таблица для TrinoTrino через Iceberg connector видит обычную SQL-таблицу с транзакциями, time travel и pruning

Открытый формат таблиц отвечает на все четыре вопроса одним механизмом: слоем метаданных рядом с файлами данных. Метаданные — это тоже файлы в том же object storage, но они описывают, какие файлы данных образуют таблицу, какая у неё схема, как она партиционирована и какая статистика у каждого файла. Каждое изменение таблицы создаёт новую версию метаданных — снапшот. Снапшот — это согласованный «список файлов на момент времени». Запрос всегда читает один конкретный снапшот, поэтому видит атомарный, целостный срез. Параллельная запись создаёт новый снапшот, не трогая старый, — отсюда атомарность и изоляция.

NOTE

Ключевая мысль модуля: формат таблиц не хранит данные. Данные — в обычных Parquet-файлах. Формат таблиц хранит метаданные о данных. Поэтому те же файлы могут читать и Trino, и Spark, и Flink — никто никого не блокирует, потому что движки координируются через общий слой метаданных, а не через монопольный доступ к файлам.

Где здесь Trino и почему именно он

Trino в lakehouse-архитектуре — это compute-слой, полностью отделённый от storage. Файлы и метаданные живут в object storage, которое не зависит от Trino. Сам Trino не хранит ничего: упал кластер — данные на месте, поднимаете новый кластер, он подключается к тому же storage. Это и есть разделение compute и storage в чистом виде: масштабируете обработку независимо от объёма данных.

Чтобы Trino понял lakehouse-таблицу, он использует коннектор формата — iceberg, delta_lake или hive. Коннектор знает, как читать слой метаданных конкретного формата: где лежит текущий снапшот, как разобрать манифесты, как достать статистику. Координатор Trino читает метаданные, получает список файлов с их min/max, отбрасывает заведомо ненужные файлы (это pruning — увидим в уроке про партиционирование) и генерирует сплиты только по оставшимся файлам. Воркеры читают Parquet-файлы напрямую из object storage параллельно.

Но коннектору нужно знать ещё одну вещь: где взять указатель на текущую таблицу. Object storage — это плоское хранилище объектов, в нём нет понятия «база данных» или «список таблиц». Должен быть отдельный реестр: «таблица orders в схеме sales — это вот такой файл метаданных по вот такому пути». Этот реестр называется каталог метаданных (metadata catalog) — Hive Metastore, AWS Glue, REST catalog, Nessie, JDBC. Не путайте его с понятием catalog в самом Trino (которое означает «коннектор плюс настройки подключения»). Каталогам метаданных целиком посвящён следующий урок.

-- Каталог Trino с именем iceberg, использующий коннектор iceberg.
-- Файл etc/catalog/iceberg.properties:
--   connector.name=iceberg
--   iceberg.catalog.type=rest
--   iceberg.rest-catalog.uri=http://rest-catalog:8181
--   fs.native-s3.enabled=true
--   s3.endpoint=http://minio:9000

-- Создаём схему. LOCATION задаёт префикс в object storage,
-- куда формат таблиц будет складывать и данные, и метаданные.
CREATE SCHEMA iceberg.sales
  WITH (location = 's3://lake/sales');

-- Создаём настоящую таблицу формата Iceberg.
CREATE TABLE iceberg.sales.orders (
  order_id    BIGINT,
  customer_id BIGINT,
  order_date  DATE,
  amount      DECIMAL(12,2)
)
WITH (format = 'PARQUET');

-- Загружаем данные. Это атомарная операция: создаётся новый снапшот.
INSERT INTO iceberg.sales.orders VALUES
  (1, 100, DATE '2026-05-01', DECIMAL '250.00'),
  (2, 101, DATE '2026-05-01', DECIMAL '99.90'),
  (3, 100, DATE '2026-05-02', DECIMAL '12.50');
-- INSERT: 3 rows

После такого INSERT в s3://lake/sales/orders/ появятся и Parquet-файлы с данными, и файлы метаданных. Любой движок, умеющий читать Iceberg, увидит ровно эти три строки — потому что они зафиксированы одним снапшотом. SELECT во время следующего INSERT увидит старый снапшот целиком, без половинчатых данных.

-- Запрос читает один согласованный снапшот таблицы.
SELECT order_date, count(*) AS orders, sum(amount) AS revenue
FROM iceberg.sales.orders
GROUP BY order_date
ORDER BY order_date;

--  order_date | orders | revenue
-- ------------+--------+---------
--  2026-05-01 |      2 |  349.90
--  2026-05-02 |      1 |   12.50

Чем lakehouse отличается от warehouse и lake — итог

СвойствоData warehouseData lakeLakehouse (Iceberg/Delta)
Формат храненияПроприетарныйОткрытый (Parquet/ORC)Открытый (Parquet/ORC)
Транзакции, атомарностьЕстьНетЕсть (через снапшоты)
Согласованный список файловЕстьНет (list не атомарен)Есть (манифесты снапшота)
Schema evolutionЕстьНетЕсть
Time travelИногдаНетЕсть
Несколько движков на одних данныхНетДа, но без гарантийДа, с гарантиями
Compute и storage разделеныЧасто нетДаДа
Статистика для оптимизатораЕстьНетЕсть (min/max в манифестах)

Lakehouse не «лучше всех по всем осям» — у зрелого warehouse транзакции отлажены десятилетиями. Но lakehouse даёт то, чего не даёт ни warehouse, ни lake: открытые данные, на которые при этом можно положиться как на таблицу, с разделением compute и storage. Для дата-инженерии 2026 года это базовая архитектура, и Trino — один из её основных compute-движков.

Попробуй сам

Зайдите на trino.io/docs/current/connector/iceberg.html и найдите раздел про требования коннектора. Ответьте на три вопроса. Первый: какие типы каталога метаданных перечислены для iceberg.catalog.type и почему коннектору вообще нужен отдельный каталог, а не просто путь в S3. Второй: коннектор требует настроенную нативную файловую систему (fs.native-s3.enabled и аналоги) — почему хранение и метаданные нельзя «зашить» в сам Trino. Третий, концептуальный: ваша команда хранит логи в s3://lake/raw-logs/ тысячами Parquet-файлов и читает их Trino через Hive-таблицу с LOCATION. Какие из четырёх проблем data lake (несогласованный list, schema evolution, атомарность записи, statistics-based pruning) сейчас бьют по вам и какие исчезнут после миграции этой таблицы в формат Iceberg? Запишите ответ своими словами — следующие уроки модуля будут опираться на это понимание.


Проверка знанийKnowledge check
Почему набор Parquet-файлов в папке object storage не является полноценной таблицей и что именно добавляет открытый формат таблиц вроде Iceberg, чтобы превратить его в таблицу?
ОтветAnswer
Набор Parquet-файлов в папке не отвечает на четыре вопроса, без которых таблица невозможна. Какие файлы входят в таблицу прямо сейчас — операция list над object storage не атомарна, и параллельная запись приводит к чтению несогласованного среза. Какая у таблицы текущая схема — разные файлы могут иметь разные схемы после истории add/drop/rename колонок. Как сделать запись атомарной — нет механизма, чтобы добавление одних файлов и удаление других было видно либо целиком, либо никак. Какие файлы можно пропустить при фильтре — нет заранее посчитанной статистики min/max по файлам. Открытый формат таблиц добавляет слой метаданных рядом с файлами данных: манифесты со списком файлов, схему, описание партиционирования и статистику. Каждое изменение создаёт новый снапшот — согласованный список файлов на момент времени. Запрос всегда читает один снапшот целиком, поэтому видит атомарный срез; параллельная запись создаёт новый снапшот, не трогая старый. Сами данные остаются в обычных открытых Parquet-файлах, поэтому их могут читать и Trino, и Spark, координируясь через общий слой метаданных.

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

Результат: 0 из 0
Концептуальный
Вопрос 1 из 4. Что именно lakehouse-архитектура берёт из data warehouse, а что — из data lake?

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

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

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

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