Каталоги метаданных: Hive Metastore, Glue, REST, Nessie, JDBC
В прошлом уроке мы выяснили: формат таблиц хранит слой метаданных рядом с данными в object storage. Но возник незакрытый вопрос. Object storage — плоское хранилище объектов: в нём нет понятия «база данных», «схема» или «список таблиц». Когда вы пишете SELECT * FROM iceberg.sales.orders, коннектору нужно откуда-то узнать, какой именно файл метаданных в S3 соответствует таблице orders прямо сейчас. Этот «откуда-то» и есть каталог метаданных. В этом уроке разберём, зачем он нужен, какую критическую функцию выполняет и чем отличаются пять его реализаций, поддерживаемых Trino.
Проблема: указатель на текущую версию таблицы
Вспомним устройство Iceberg-таблицы. Каждое изменение создаёт новый файл метаданных — назовём его metadata-файлом. После трёх INSERT в object storage лежат три metadata-файла: v1.metadata.json, v2.metadata.json, v3.metadata.json. Каждый описывает таблицу на свой момент времени. Текущее состояние таблицы — это v3. Но завтра будет v7, а через месяц v200.
Возникает вопрос: как читатель узнаёт, какой metadata-файл сейчас актуальный? Сканировать папку и брать «самый свежий» нельзя — мы уже знаем, что list над object storage не атомарен и не упорядочен надёжно, а во время записи там вообще лежит ещё не зафиксированный файл. Нужен один-единственный надёжный источник правды, который хранит ровно одну запись: «текущий metadata-файл таблицы sales.orders — это s3://lake/sales/orders/metadata/v3.metadata.json».
Этот реестр и называется каталогом метаданных. Его единственная по-настоящему критичная задача — хранить указатель «имя таблицы -> путь к текущему metadata-файлу» и менять его атомарно. Всё остальное (список схем, список таблиц) — производное.
Apache Iceberg: архитектура каталога и иерархия метаданныхЗачем атомарность каталога: коммит и оптимистичная блокировка
Самая важная функция каталога — не чтение, а атомарная смена указателя при коммите. Разберём, что происходит при INSERT.
Воркеры Trino пишут новые Parquet-файлы в object storage. Затем координатор формирует новый metadata-файл v4.metadata.json, описывающий таблицу с этими файлами, и тоже кладёт его в S3. Пока всё это происходит, таблица для читателей по-прежнему v3 — указатель в каталоге не тронут. Финальный шаг коммита: попросить каталог сменить указатель с v3 на v4. И вот этот шаг обязан быть атомарным и условным.
Условность важна, потому что писать в таблицу может кто-то ещё одновременно. Каталог выполняет операцию compare-and-swap: «смени указатель на v4, но только если он сейчас всё ещё v3». Это оптимистичная конкуренция. Если две записи стартовали от v3, первая успеет: указатель станет v4. Вторая придёт со своим v4, каталог увидит, что текущее значение уже не v3, и отклонит коммит. Проигравшая запись перечитает актуальное состояние и повторит попытку поверх v4. Без атомарного compare-and-swap в каталоге две параллельные записи затёрли бы изменения друг друга — это была бы потеря данных.
Object storage сам по себе долго не давал атомарного compare-and-swap на объект — отсюда исторически и нужен внешний каталог. Современные S3 умеют conditional writes, и появляются «безкаталожные» подходы, но в Trino-практике 2026 года Iceberg-таблица почти всегда живёт под управлением одного из пяти каталогов ниже. Выбор каталога — это выбор того, кто хранит указатель и как делает атомарный коммит.
Пять реализаций каталога в Trino
iceberg.catalog.type в файле каталога Trino задаёт реализацию. Разберём пять основных.
Hive Metastore (HMS) — iceberg.catalog.type=hive_metastore. Исторически первый каталог, исходно созданный для Hive-таблиц. Это отдельный Java-сервис с реляционной БД под капотом (PostgreSQL или MySQL), общающийся по Thrift-протоколу (hive.metastore.uri=thrift://...). Указатель таблицы и compare-and-swap живут в этой реляционной БД — она и даёт атомарность. Плюс: проверен годами, его понимают все движки. Минусы: это лишний сервис, который надо разворачивать, обслуживать и масштабировать; Thrift-протокол тяжёл; HMS — частая точка отказа в lakehouse-стеке.
AWS Glue Data Catalog — iceberg.catalog.type=glue. Это managed-аналог HMS от AWS: тот же реестр таблиц, но как сервис, который не нужно разворачивать самому. Атомарность коммита обеспечивает Glue. Естественный выбор, если инфраструктура уже в AWS. Минус — привязка к AWS.
REST catalog — iceberg.catalog.type=rest. Современный стандарт. Iceberg определяет открытую REST-спецификацию: любой сервис, реализующий её, становится каталогом, а движок общается с ним по HTTP. Trino — просто HTTP-клиент (iceberg.rest-catalog.uri=http://...). Где живёт указатель и как делается атомарный коммит — внутреннее дело сервиса; для Trino это чёрный ящик за стабильным API. Под REST-спецификацию есть несколько серверов; среди них — Nessie. Плюсы: открытый стандарт, лёгкий HTTP вместо Thrift, движок не зависит от устройства каталога. В новых проектах REST — выбор по умолчанию.
Nessie — iceberg.catalog.type=nessie. Project Nessie добавляет к каталогу версионирование уровня каталога в стиле Git: ветки и теги не для одной таблицы, а для всего каталога. Можно создать ветку, наполнить в ней десять таблиц новыми данными, проверить и атомарно «смержить» весь набор изменений сразу. Nessie реализует и REST-спецификацию Iceberg, поэтому к нему можно подключаться и как rest, и через нативный nessie-тип. Выбор, когда нужны мульти-табличные согласованные изменения и Git-подобный workflow для данных.
JDBC catalog — iceberg.catalog.type=jdbc. Самый лёгкий вариант: указатель хранится прямо в реляционной БД (PostgreSQL/MySQL) в простой таблице, Trino ходит туда по JDBC. Никакого отдельного metastore-сервиса — нужна только сама БД. Атомарность даёт транзакция этой БД. Удобно для разработки, тестов, небольших инсталляций. Минус — за пределами Trino такой каталог понимают не все инструменты так же гладко, как HMS или REST.
Как это выглядит в конфигурации
Каждый файл каталога Trino (etc/catalog/iceberg.properties) задаёт коннектор и тип каталога метаданных.
# Вариант с REST catalog (рекомендуемый для новых проектов)
connector.name=iceberg
iceberg.catalog.type=rest
iceberg.rest-catalog.uri=http://rest-catalog:8181
iceberg.rest-catalog.warehouse=s3://lake/warehouse
fs.native-s3.enabled=true
s3.endpoint=http://minio:9000
s3.path-style-access=true
# Вариант с Hive Metastore
connector.name=iceberg
iceberg.catalog.type=hive_metastore
hive.metastore.uri=thrift://hms:9083
fs.native-s3.enabled=true
s3.endpoint=http://minio:9000
После настройки тип каталога становится для SQL прозрачным — DDL и DML выглядят одинаково:
CREATE SCHEMA iceberg.sales WITH (location = 's3://lake/sales');
CREATE TABLE iceberg.sales.orders (
order_id BIGINT,
order_date DATE,
amount DECIMAL(12,2)
) WITH (format = 'PARQUET');
INSERT INTO iceberg.sales.orders
VALUES (1, DATE '2026-05-01', DECIMAL '250.00');
-- INSERT: 1 row
Различие проявляется в служебных операциях. register_table — процедура, регистрирующая в каталоге уже существующие в object storage метаданные (например, таблицу создал Spark, а вы хотите видеть её в Trino). Она зависит от того, поддерживает ли конкретный каталог такую операцию:
-- Зарегистрировать существующие метаданные Iceberg в каталоге Trino.
-- Доступность зависит от типа каталога.
CALL iceberg.system.register_table(
schema_name => 'sales',
table_name => 'orders_external',
table_location => 's3://lake/external/orders'
);
Какой каталог выбрать
| Каталог | Отдельный сервис | Атомарность коммита | Когда выбирать |
|---|---|---|---|
| Hive Metastore | Да (Thrift + БД) | Реляционная БД | Legacy-стек, уже есть HMS, нужна совместимость с Hive-инструментами |
| AWS Glue | Нет (managed) | Сервис Glue | Инфраструктура в AWS, не хочется обслуживать metastore |
| REST | Да (HTTP-сервис) | Скрыта за API | Новые проекты: открытый стандарт, лёгкий протокол |
| Nessie | Да (HTTP-сервис) | Скрыта за API | Нужны Git-ветки и теги на уровне всего каталога |
| JDBC | Нет (только БД) | Транзакция БД | Разработка, тесты, небольшие инсталляции |
Практический ориентир 2026 года: для новых продакшен-инсталляций — REST catalog (открытый стандарт, минимум связности с устройством каталога). Если нужны мульти-табличные согласованные изменения — Nessie. В AWS — Glue ради managed-простоты. HMS — когда стек уже построен вокруг него. JDBC — для локальной разработки и небольших установок. Выбор каталога не влияет на SQL и формат данных — он влияет только на то, кто хранит указатель таблицы и как делает атомарный коммит.
Попробуй сам
Откройте trino.io/docs/current/connector/iceberg.html и найдите таблицу значений iceberg.catalog.type. Выпишите все поддерживаемые значения и для каждого — обязательное свойство конфигурации (например, для rest это iceberg.rest-catalog.uri). Затем разберите два сценария. Сценарий первый: у вас три кластера Trino, плюс отдельные пайплайны Spark, и все они должны писать в одни и те же Iceberg-таблицы. Какой механизм каталога гарантирует, что параллельные коммиты двух движков не затрут друг друга, и что произойдёт с коммитом, который пришёл вторым? Сценарий второй: вы хотите подготовить большое обновление сразу для пятнадцати витрин, проверить его целиком и опубликовать одним атомарным шагом. Какой из пяти каталогов даёт такую возможность и за счёт какой своей особенности? Сформулируйте ответы письменно.