Лейкхаус на Apache Iceberg

Озеро вместо DWH

|
Лейкхаус на Apache Iceberg

Ваши данные живут в двух местах, и оба вас раздражают. Data Lake (озеро) — дёшево и масштабируется до петабайт, но это дикий запад: никаких транзакций, никакого порядка, один недописанный джоб — и вы уже не уверены, что в таблице правда. Data Warehouse (DWH) — быстро, под контролем, с ACID, но счёт за хранение растёт как на дрожжах, а любой Python-скрипт из ML-команды смотрит на него с подозрением. Между ними день и ночь молотит ETL, который копирует, трансформирует и сверяет одно и то же — и это вечный налог на инженерное время, свежесть данных и бюджет.

Знакомая картина? Дашборды показывают вчерашние цифры, потому что DWH грузится по ночам. ML-модели учатся на устаревших копиях, потому что DWH не дружит с нативным Python-доступом. Хранилище дорожает, потому что одни и те же наборы лежат в двух системах сразу. А управление данными фрагментировано: доступы, lineage и аудит не умеют жить одновременно в двух архитектурно разных платформах.

Лейкхаус закрывает этот цирк одним ударом: транзакционные гарантии прямо на объектном хранилище. Одна копия. Одна модель управления. Любой движок — SQL, ML, стриминг, ИИ-агент — читает и пишет одни и те же таблицы с полной ACID-безопасностью. DWH при этом не заменяется другим продуктом: озеро становится DWH благодаря метаданной инновации, которая называется табличным форматом.

Уже читали про DuckDB и Iceberg или про пять причин медленных запросов? Этот пост — обзор всей архитектуры целиком: от байтов в S3 до ИИ-агентов, которые шлют запросы к тем же таблицам.

Ниже — как лейкхаус реально работает: четыре слоя, дерево метаданных Iceberg, медальонная архитектура, почему любая прод-таблица деградирует без обслуживания и как с этим жить.

Четыре слоя лейкхауса

Лейкхаус — не монолит. Это четыре сотрудничающих слоя, у каждого своя зона ответственности, и каждый эволюционирует независимо. Понять, как они взаимодействуют, — фундамент для того, чтобы построить лейкхаус, который не развалится в проде.

flowchart LR
  A[Объектное хранилище<br/>S3 / GCS / ADLS] --> B[Табличный формат<br/>Apache Iceberg]
  B --> C[Каталог<br/>REST: Glue / Polaris / Nessie]
  C --> D[Spark]
  C --> E[Trino]
  C --> F[Flink]
  C --> G[DuckDB]
  D --> H[Таблицы Iceberg]
  E --> H
  F --> H
  G --> H

Слой 1: объектное хранилище

Все данные живут на облачном объектном хранилище — S3, GCS или ADLS. Здесь рождается экономика: долговечность одиннадцать девяток при 1 800–2 250 ₽ за терабайт в год. Петабайт аналитических данных обходится примерно в 1 800 000 ₽ в год — против 45 000 000 ₽+, если те же данные лежат внутри традиционного DWH с привязанными к нему вычислениями.

Хранилище отвязано от всего, что выше. Потуши все движки запросов — данные останутся. Завтра добавишь новый движок — он прочитает тот же бакет. Переедешь между облаками — файлы скопируются байт-в-байт, без конвертации формата.

Данные ложатся как Parquet — колоночный формат, который хранит значения по колонкам, а не по строкам. Запрос, трогающий 5 колонок из 300, физически читает только эти 5. Плюс Parquet встраивает в заголовок каждого файла min/max статистику по колонкам, и движки умеют пропускать целые файлы, чьи диапазоны значений не пересекаются с WHERE. Именно этот скип-скан делает лейкхаус-запросы конкурентными DWH-запросам — но только пока файлы правильно упакованы и организованы.

Слой 2: табличный формат — Apache Iceberg

Каталог Parquet-файлов в S3 — это озеро: читаемое, но не транзакционное. Табличный формат — та самая метаданная инновация, которая добавляет недостающие гарантии.

Apache Iceberg — доминирующий открытый табличный формат: его нативно читают Spark, Trino, Flink, DuckDB, Snowflake, Databricks, Athena и StarRocks. Он даёт ACID-коммиты, эволюцию схемы, time travel, эволюцию партиций и безопасную конкурентную запись через архитектуру дерева метаданных. Формат перешёл из стадии внедрения в стадию оптимизации: сообщество уже занято фичами V3 (deletion vectors, lineage строк) и спецификацией V4. Каждый механизм — от атомарных коммитов до time travel — детально разобран в бесплатном курсе по Apache Iceberg.

Слой 3: каталог

Каталог — координационный сервис, который отвечает на два вопроса: где сейчас указатель на метаданные таблицы и как нескольким движкам безопасно координировать запись.

Каждый движок обращается к каталогу перед чтением (найти текущие метаданные) и во время записи (атомарно закоммитить). Без каталога конкурентные писатели могли бы испортить состояние таблицы. С ним они соревнуются безопасно: один коммитит, другой ретраит против обновлённого состояния.

Современные лейкхаусы используют спецификацию Iceberg REST Catalog — стандартный HTTP API, который реализует каждый движок. Добавить новый движок — это изменение конфигурации (укажи URL каталога), а не интеграционный проект. Варианты каталогов: управляемые сервисы (AWS Glue), open-source серверы (Apache Polaris, Lakekeeper), федеративные решения (Apache Gravitino), git-ветвление (Project Nessie) — и все говорят на одном REST-протоколе. В каталоге же материализуются доступы, политики ретеншена и аудит — это якорь управления в мультидвижковом окружении. Подробнее о том, чем каталоги отличаются друг от друга, — в уроке про каталоги из курса по Iceberg.

Слой 4: движки вычислений

Лейкхаус разделяет compute и storage, позволяя нескольким специализированным движкам работать с одними данными параллельно:

  • Spark — пакетный ETL, ML-обучение, сложные многоступенчатые трансформации. Рабочая лошадка тяжёлых записей и джойнов.
  • Trino — интерактивный SQL с субсекундными ответами. Король дашбордов и ad-hoc разведки.
  • Flink — стриминговое вливание с exactly-once семантикой. Непрерывный CDC из операционных баз.
  • DuckDB — встраиваемая аналитика для ноутбуков, CI/CD и однопроцессных задач. Ноль инфраструктуры.
  • Snowflake / Athena / StarRocks — управляемые движки под конкретные профили нагрузки.

Каждый движок находит таблицы через тот же REST-каталог и читает/пишет по транзакционному протоколу Iceberg. Они мирно сосуществуют на одних таблицах благодаря snapshot isolation. В этом главное архитектурное преимущество над DWH: вместо одного вендорского движка на всё — лучший инструмент под каждую форму нагрузки.

Но мультидвижковость умножает операционное давление. Больше движков — больше паттернов записи, больше профилей фрагментации файлов, больше конкурирующих паттернов запросов за одну физическую раскладку. Это и есть та операционная задача, которая определяет жизнь продакшн-лейкхауса.

Как устроено дерево метаданных Iceberg

Каждая таблица Iceberg держит иерархию файлов метаданных там же, где данные:

  1. Указатель метаданных (хранится в каталоге) — ссылка на текущую версию таблицы.
  2. Снапшоты — полное состояние таблицы на момент времени. Каждая запись создаёт новый снапшот.
  3. Manifest list — каждый снапшот ссылается на список активных манифестов.
  4. Манифесты — каждый отслеживает пачку файлов данных со статистикой: путь, значения партиций, число строк, min/max по колонкам.
  5. Файлы данных — собственно Parquet-файлы со строками.
flowchart TD
  A[Указатель в каталоге] --> B[Снапшот]
  B --> C[Manifest list]
  C --> D1[Манифест]
  C --> D2[Манифест]
  D1 --> E1[Файлы данных Parquet]
  D2 --> E2[Файлы данных Parquet]

Это дерево даёт два свойства, без которых лейкхаус нежизнеспособен:

Атомарные коммиты. Каждая запись производит новые файлы данных и новый снапшот. Каталог атомарно меняет указатель со старого снапшота на новый. Читатели всегда видят консистентное состояние. Упавшая запись не оставляет следов — указатель просто не продвинулся.

Статистический прунинг. Движки читают манифесты (килобайты), чтобы понять, какие файлы данных (гигабайты) релевантны. Запрос с фильтром country = 'DE' проверяет статистику на уровне манифестов и пропускает каждый файл, чей диапазон min/max по country исключает 'DE'. Ноль чтения. Ноль потраченного I/O. Так лейкхаус-запросы догоняют DWH-запросы — но только когда метаданные свежие, а раскладка файлов совпадает с паттернами запросов.

Критическое следствие: каждый коммит растит дерево. Каждая стриминговая запись добавляет файлы. Каждая мутация добавляет delete-маркеры. Дерево, которое делает запросы быстрыми, одновременно копит энтропию, которая эти запросы замедляет — если кто-то активно его не обслуживает.

Медальонная архитектура: бронза, серебро, золото

Как данные реально текут от источников к потребителям? Стандартный паттерн — медальонная архитектура (bronze → silver → gold), и у каждого уровня свои операционные особенности, которые важны для долгосрочного здоровья.

Бронза: сырой приём

Исходные данные ложатся в первозданном виде: CDC-события из PostgreSQL через Debezium и Flink, кликстрим из Kafka, ежедневные выгрузки из SaaS-API, файлы от партнёров. Всё append-only, schema-on-read, неизменяемо.

Бронза — источник для воспроизведения. Нашёл баг в логике серебряного слоя спустя месяцы? Пересобираешь из бронзы. Появился новый use case, которому нужны раньше игнорировавшиеся поля? Они уже сохранены. Эта неизменяемость не подлежит обсуждению — команды, применяющие трансформации прямо на приёме, теряют возможность задним числом исправить ошибки логики.

Что это значит операционно: стриминговый CDC с коммитами раз в 5 минут создаёт примерно 8 600 файлов на таблицу в месяц. Лейкхаус, вливающий данные из 20 операционных баз с субминутной задержкой, за недели накапливает сотни тысяч файлов только в бронзе. Средний размер файла — 5–20 МБ при целевых 256–512 МБ, где движки работают оптимально. Скорость планирования запросов убивает именно число файлов, а не объём данных.

Серебро: управляемая правда

Серебро превращает бронзу в модель данных, за которую организация готова отвечать: одна строка на сущность, разрешённые внешние ключи, дедуплицированные события, приведённые типы, отбракованные плохие записи. Серебро — не шаг уборки, а архитектурное обязательство перед доменной моделью, от которой зависят все нижестоящие потребители.

Ключевые трансформации: дедупликация (разрешение поздних записей и повторов через MERGE INTO), контроль и валидация типов, медленно меняющиеся измерения (SCD Type 2), обогащение справочниками. У каждого паттерна — свои последствия для записи.

Что это значит операционно: серебряные таблицы получают MERGE INTO — апсерты, которые создают delete-маркеры (position-delete файлы или deletion vectors в V3), и каждый последующий read обязан их применять. CDC-таблица с 50 000 обновлений в час генерирует тысячи маркеров в день. Без периодического схлопывания маркеров латентность запросов ползёт вверх в 2–5 раз — при этом число строк и размер таблицы не меняются, и обычный мониторинг ничего не замечает.

Золото: слой под потребителя

Золотые таблицы существуют ради производительности: предагрегированные метрики для дашбордов, денормализованные фичи для ML-обучения, материализованные срезы для комплаенс-отчётности. Золото платит избыточностью хранения за скорость чтения.

Что это значит операционно: золотые таблицы обычно перезаписываются по расписанию — ежедневно, ежечасно или по сигналу свежести апстрима. Каждый OVERWRITE атомарно заменяет содержимое таблицы, но оставляет файлы прошлых снапшотов в хранилище, пока снапшоты явно не протухнут. Ежедневный рефреш золота создаёт 365 снапшотов в год. При 50 ГБ на рефреш это 18 ТБ устаревших файлов, которые физически лежат в хранилище, хотя логически актуальны только последние 50 ГБ. Без управления жизненным циклом снапшотов хранилище растёт линейно вечно — из данных, заменённых недели или месяцы назад.

Градиент обслуживания

Три уровня создают градиент операционных потребностей:

  • Бронза — давление мелких файлов (приоритет: компакция)
  • Серебро — давление delete-файлов (приоритет: схлопывание удалений)
  • Золото — давление устаревших снапшотов (приоритет: экспайр)

Единое расписание обслуживания не способно закрыть все три случая. Каждой таблице нужна правильная операция в правильном ритме — определяемом скоростью вливания, паттерном мутаций и запросной нагрузкой.

Почему лейкхаус деградирует

Большинство гайдов про лейкхаус заканчиваются на четырёх слоях. И зря: слои дают архитектуру, но не дают систему, которая остаётся здоровой. Любой продакшн-лейкхаус — без исключений — деградирует со временем, если его активно не обслуживать. Это не баг, а фундаментальное следствие устройства append-only транзакционных систем. Детальный разбор того, как фрагментация файлов и разросшиеся метаданные замедляют запросы, — в посте о пяти причинах медленных запросов.

Механика деградации. Iceberg никогда не правит файлы на месте — каждая запись создаёт новые файлы, каждый снапшот сохраняет полное состояние. Это даёт транзакционную безопасность, но система непрерывно копит структурный долг:

  • Фрагментация файлов. Каждый коммит добавляет файлы. Стриминг с интервалом 5 минут — ~8 600 файлов на таблицу в месяц по ~12 МБ. Движку приходится открывать, планировать и координировать чтение в сто раз большего числа файлов, чем нужно.
  • Накладные расходы планирования. Планировщики обходят дерево манифестов. При 1 000 файлов планирование занимает миллисекунды; при 50 000 — 10–20 секунд, иногда больше самого выполнения запроса.
  • Накопление delete-файлов. Каждый UPDATE и DELETE пишет маркеры, которые читатели обязаны применять. Сильно мутируемая таблица копит тысячи маркеров — латентность растёт в 2–5 раз при неизменных числе строк и размере.
  • Мусор в хранилище. Протухшее логическое содержимое оставляет физические файлы. Orphan-файлы от упавших записей, отменённых компакций и протухших снапшотов копятся терабайтами — чистый расход без аналитической ценности.
  • Усиливающее давление. Эти силы не независимы — они усиливают друг друга. Больше файлов → больше манифестов → медленнее планирование → медленнее обслуживание → реже запуски → ещё больше файлов. Система имеет естественную склонность к разгоняющейся деградации.

Почему ручные скрипты не масштабируются. Инстинкт — написать скрипты: Spark-джоб, компактящий каждую таблицу ночью, cron, протухающий снапшоты еженедельно. Это работает для 5–10 таблиц и разваливается в проде по структурным причинам:

  • Разные кадэнсы. Стриминговая таблица требует компакции ежечасно, таблица с ежедневным рефрешем — еженедельно, медленно растущий справочник — ежемесячно. Одно расписание не обслуживает все три: либо ты жжёшь compute на здоровых таблицах, либо запускаешь обслуживание, когда таблицы уже деградировали.
  • Зависимости операций. Компактить файлы, которые через час протухнут, — впустую. Переписывать манифесты до компакции — обесценить переписывание. Пять операций обслуживания должны идти в определённой последовательности и перестраиваться при изменении условий.
  • Статические пороги дрейфуют. «Компактить, когда файлов больше 1 000» — разумно для текущего состояния одной таблицы. Но кардинальность партиций меняется, скорость вливания сдвигается, паттерны запросов эволюционируют. Порог, верный в прошлом месяце, сегодня неверен — и никто его не поправляет, пока таблица уже не деградировала.
  • Стоимость выполнения. Прогон Spark-кластеров ради переписывания файлов стоит порядка 4 500 ₽ за терабайт compute. Команды вынуждены ограничиваться ночными окнами, в которые таблицы деградируют 23 часа между проходами.

Обслуживание: пять операций в правильном порядке

Ответ — не «лучше скрипты» и не «умнее cron», а подход, при котором обслуживание становится непрерывным замкнутым процессом: сенсорика состояния таблиц, оценка здоровья, планирование операций в правильном порядке, исполнение и учёт результатов.

Цикл обслуживания любой таблицы — это последовательность из пяти операций, где результат каждой становится входом следующей:

  1. Протухание снапшотов — удалить снапшоты за пределами политики ретеншена. Это разыменовывает больше не нужные файлы и сужает фронт работ для следующих шагов.
  2. Удаление orphan-файлов — стереть неразыменованные файлы старше окна безопасности: то, что освободил экспайр, плюс мусор от упавших записей.
  3. Компакция файлов данных — слить мелкие файлы в оптимальные по размеру, схлопнуть delete-маркеры, чтобы последующие чтения не платили за их применение. Опционально — отсортировать по релевантным колонкам для статистического прунинга.
  4. Переписывание манифестов — консолидировать дерево манифестов под новую раскладку.
  5. Пересчёт статистики — обновить Puffin-статистику колонок на скомпактированных файлах для точного прунинга.
-- Пример: каскад обслуживания таблицы через хранимые процедуры SparkCALL catalog.system.expire_snapshots(  table => 'db.orders', older_than => TIMESTAMP '2026-09-24 00:00:00', retain_last => 5);CALL catalog.system.remove_orphan_files(table => 'db.orders', older_than => TIMESTAMP '2026-09-27 00:00:00');CALL catalog.system.rewrite_data_files(  table => 'db.orders', strategy => 'sort',  sort_order => 'customer_id ASC NULLS LAST, event_date ASC NULLS LAST');CALL catalog.system.rewrite_manifests(table => 'db.orders');

Адаптивное обслуживание запускает каждую операцию, когда сигналы здоровья показывают необходимость, соблюдая порядок зависимостей: стриминговые таблицы компактятся несколько раз в час, пакетные — раз в день, здоровые — пропускаются. Оно не конфликтует с активными писателями: партиции с активными писателями исключаются, OCC-конфликты ретраятся автоматически, снапшоты, на которые опираются читатели, не протухают.

Самая большая недооценённая опция — сортировка под реальные запросы. Обычная компакция сливает мелкие файлы в крупные — полезно, но это лишь половина оптимизации. Настоящий рычаг — сортировка данных по колонкам, по которым продакшн-запросы реально фильтруют. Когда диапазон значений сортировочных колонок в каждом файле узок, статистический прунинг становится хирургическим: движок проверяет min/max на уровне файлов и отсекает 90%+ файлов до чтения данных. Разница между несортированной и правильно отсортированной таблицей — типичные 8–12× в скорости запросов.

Проблема в том, что ни один движок не видит полную картину. Trino фильтрует по customer_id, Spark — по event_date, и таблице нужен порядок, обслуживающий обоих. Решение — агрегировать телеграмметрию WHERE/JOIN/GROUP BY со всех подключённых движков и вычислять порядок сортировки автоматически, обновляя его при сдвиге паттернов. А перед коммитом любой стратегии в прод — прогнать симуляции раскладки на Iceberg-ветках: воспроизвести реальные паттерны запросов против предлагаемой раскладки и замерить сокращение скана. Плохое решение поймается до того, как коснётся продакшн-данных.

Политики вместо скриптов

Видимость без исполнения — просто мониторинг. Наблюдаемость превращается в автоматизированное управление через декларативные политики, работающие на нескольких уровнях:

  • Дефолты уровня организации — базовые цели компакции, ретеншен снапшотов, расписания очистки orphan-файлов для всех таблиц, если не переопределено.
  • Правила уровня неймспейса — продакшн-неймспейсы получают агрессивное обслуживание, staging — расслабленные пороги.
  • Исключения уровня таблицы — комплаенс-таблицы с ретеншеном 365 дней, горячие таблицы с 15-минутным каденсом компакции.

Политики наследуются вниз: новая таблица автоматически получает правила своего неймспейса. Никакой ручной конфигурации на таблицу, никаких «забыли добавить в скрипт». Каждое исполнение логируется с полным аудит-трейлом: что запускалось, когда, что изменилось, сколько байт было и стало. Для комплаенс-окружений это критично.

Маршрутизация запросов между движками

Несколько движков на одних данных — архитектурно элегантно. Но без интеллекта маршрутизации это становится случайно дорого: запрос, отправленный не в тот движок, платит не ту ценовую модель и получает не тот профиль производительности.

Точечный запрос на 100 строк, отправленный в Spark, сжигает 30 секунд на старт кластера. Тот же запрос на DuckDB решается за 0,3 секунды. Дашборд-запрос на Snowflake по 180 ₽ за кредит в 10 раз дороже того же запроса на self-hosted Trino. Полный скан таблицы роняет DuckDB, а Spark справляется за минуты.

Маршрутизация даёт единую SQL-точку входа, которая диспетчеризует запросы в оптимальный движок по форме нагрузки, состоянию здоровья таблиц и целям по стоимости/латентности. Определяешь группы маршрутизации — analytics, BI, ETL, отчёты — каждая со стабильным endpoint и своей стратегией оптимизации:

  • Analytics (интерактив, ad-hoc) → DuckDB + Trino, субсекундные ответы
  • BI (дашборды, отчёты) → Trino + Snowflake, конкурентный доступ
  • ETL (трансформации, пайплайны) → Spark + Athena, пропускная способность
  • ИИ-агенты → DuckDB + Trino через MCP, с лимитами бюджета и guardrails

Из открытых реализаций такого слоя показателен QueryFlux — Rust-роутер, который принимает запросы по Trino/PostgreSQL/MySQL/Snowflake-протоколам, автоматически переводит диалекты SQL через sqlglot и диспетчеризует их между Trino, DuckDB, StarRocks, Athena и ClickHouse, с очередями и метриками Prometheus. Проект молодой, но точно иллюстрирует категорию: единая точка входа над специализированными движками на общих таблицах.

Слой маршрутизации и слой обслуживания образуют усиливающую петлю: компакция и сортировка делают больше движков пригодными под каждую форму запроса; больше вариантов — ниже стоимость запроса; ниже стоимость — чаще запросы; больше запросов — лучше телеграмметрия для решений о компакции.

ИИ-агенты как потребители

ИИ-агент не может диагностировать медленный запрос, вызванный деградацией таблицы. Он не отличит «таких данных нет» от «запрос тормозит, потому что таблице нужна компакция». Упершись в деградированную таблицу, агент ретраит, ловит таймаут или галлюцинирует — деградируя качество ответов, не вскрывая корневую причину. Инфраструктура должна быть здоровой до того, как агент начнёт запрашивать, а не чиниться после его провалов.

Правильный доступ агентов — через MCP-интерфейс с совместимостью по проводам PostgreSQL/MySQL/Arrow Flight: любой MCP-совместимый агент обнаруживает каталоги, просматривает схемы, выполняет запросы и получает результаты — без кастомной интеграции под каждый фреймворк.

И обязательные guardrails на сессию:

  • ReadOnly — блокирует DDL и DML.
  • ScanBudget — отклоняет запросы, чей оценочный скан превышает порог.
  • PII Mask — хеширует чувствительные колонки до того, как результат уйдёт в модель.
  • HumanApproval — ставит на паузу опасные операции для ручного подтверждения.

Guardrails конфигурируются один раз и применяются единообразно ко всем подключениям агентов — независимо от фреймворка, движка и таблицы. А телеграмметрия агентских запросов кормит обратно приоритеты компакции и веса маршрутизации: таблицы, которые агенты опрашивают активно, получают приоритет обслуживания, а порядки сортировки адаптируются под агентские паттерны.

Экономика: почему это дешевле

Преимущество лейкхауса в стоимости складывается из четырёх уровней, которые усиливают друг друга:

Развязка хранилища. Объектное хранилище — 1 800–2 250 ₽/TB/год против 45 000–180 000 ₽/TB/год у DWH. Для 200 ТБ курируемых данных это 360 000–450 000 ₽ в год против 9 000 000–36 000 000 ₽. На петабайтном масштабе экономия окупает целые платформенные команды.

Исчезновение дублирования. ETL «озеро → DWH», который копирует, трансформирует и сверяет, пропадает: вместе с ним уходят compute ETL, инженерные часы на поддержку, стоимость DWH-копии и сверка при расхождении копий.

Эффективность маршрутизации. Когда каждый запрос бежит на самом дешёвом движке, удовлетворяющем требования по латентности, совокупный compute падает радикально. Без маршрутизации организации по умолчанию платят DWH-тарифы за всё подряд.

Дешёвое обслуживание. Непрерывное обслуживание на специализированном движке компакции обходится на порядок дешевле ночных Spark-окон — а значит, оно может идти фоном, а не раз в сутки, и таблицы не успевают накопить долг между проходами.

В сумме организации с 500+ ТБ данных сообщают о снижении совокупной стоимости в 3–5 раз против связки «DWH плюс озеро».

Внедрение: с чего начать

Полная архитектура не нужна в первый день. Каждый шаг даёт самостоятельную ценность и готовит следующий:

  1. Начни с Iceberg — выбирай его для всех новых аналитических таблиц. Поддержка экосистемы универсальна, каждый крупный движок читает и пишет формат нативно. Существующие Delta Lake-таблицы интероперабельны через UniForm.
  2. Подними REST-каталог — это точка координации, её стоит сделать правильно с самого начала. AWS Glue — для управляемой простоты, self-hosted Polaris — для полного контроля, Gravitino — если нужна федерация поверх существующих каталогов.
  3. Построй слой вливания (бронзу) — CDC из операционных баз через Flink, событийные потоки, пакетные загрузки. Append-only и неизменяемо.
  4. Построй семантический слой (серебро) — доменное моделирование, дедупликация, контроль качества. Это управляемая правда организации, от которой начинается каждый нижестоящий потребитель.
  5. Подключи слой обслуживания — как только данные потекли и таблицы накопились, соедини систему обслуживания со своим каталогом. Десять минут, без движения данных и изменения инфраструктуры — и у тебя мгновенная видимость здоровья каждой таблицы. Начни в режиме ручного подтверждения: посмотри, что система рекомендует, прежде чем включать автономное исполнение. Потом включай автопилот и дай замкнутому циклу работать.
  6. Добавляй специализированные движки — по мере роста нагрузки: Trino для интерактивного SQL, DuckDB для ноутбуков, Snowflake для управляемого BI. REST-каталог делает каждое добавление шагом конфигурации.
  7. Включай маршрутизацию и доступ агентов — с тремя и более движками определи группы маршрутизации и отдай диспетчеризацию системе. Открой таблицы агентам через MCP с guardrails по типам. Телеграмметрия агентов вернётся в приоритеты оптимизации, и таблицы начнут адаптироваться под агентские нагрузки автоматически.

Озеро, DWH или лейкхаус

Характеристика Озеро DWH Лейкхаус
Модель хранения Открытые файлы на объектном хранилище Проприетарный формат, вендорское хранилище Открытые файлы на объектном хранилище
Транзакции Нет Полный ACID Полный ACID (табличный формат)
Управление Ручное, фрагментированное Вендорское, централизованное Единое через каталог, мультидвижковое
Скорость запросов Зависит только от обслуживания Стабильная, вендор-оптимизированная Как в DWH — при условии обслуживания
Гибкость движков Любой инструмент читает файлы Только движок вендора Несколько движков, REST-каталог
ML/AI-нагрузки Нативные, но неуправляемые Только экспорт Нативные и управляемые
Стриминг Отдельная инфраструктура Отдельная инфраструктура Те же таблицы, те же транзакции
Стоимость на петабайте ~1,8 млн ₽/год за хранилище 45 млн ₽+/год хранилище + compute ~1,8 млн ₽/год хранилище + операции
Бремя обслуживания Нет (нет транзакций) Ноль (вендор) Требует слоя обслуживания
Зависимость от вендора Низкая Высокая Низкая (открытые форматы + каталог)

Лейкхаус занимает конкретную нишу: DWH-гарантии при озёрной экономике, с той оговоркой, что операционное обслуживание — твоя ответственность, а не вендорская. Именно слой обслуживания делает этот размен жизнеспособным в масштабе — давая вендорскую лёгкость эксплуатации без вендорского лок-ина.

Когда строить лейкхаус

Не каждой команде нужна эта архитектура. Команда с одним движком и одним типом нагрузки на умеренном масштабе получит разумную ценность от управляемого DWH без операционной сложности. Но лейкхаус становится правильным выбором, когда:

  • Сосуществуют несколько типов нагрузки — BI, ML, стриминг и ИИ-агенты нуждаются в одних данных с разными паттернами доступа и разными движками.
  • Масштаб делает экономику значимой — выше 50–100 ТБ аналитических данных разница в стоимости хранения (10–50×) становится достаточной, чтобы оплачивать целую платформенную команду.
  • Мультидвижковость — требование — разным командам реально нужны разные движки: Spark для ETL, Trino для интерактива, Flink для стриминга, DuckDB для разработки.
  • Независимость от вендора — приоритет — открытые форматы на своём хранилище означают, что ни один вендор не контролирует твой выход; каждое компонентное решение обратимо.
  • AI/ML — полноценная нагрузка — модели и агенты нуждаются в нативном управляемом доступе к аналитическим данным, а не в экспортах, API-обёртках и устаревших копиях в отдельных фича-сторах.

Если применимо три пункта и больше — лейкхаус это не перспективное рассмотрение, а архитектура, к которой стоит строить уже сейчас.

Итог

Лейкхаус — производственный стандарт для команд, которым нужны BI, ML, стриминг и ИИ на одних управляемых данных — без DWH-цен и без компромиссов по качеству озера.

Собрать его — задача архитектурная: объектное хранилище ради экономики, Apache Iceberg ради транзакционных гарантий, REST-каталог ради координации, специализированные движки ради исполнения.

Эксплуатировать — задача системная: таблицы деградируют через фрагментацию файлов, рост метаданных, накопление delete-файлов и мусор в хранилище. Бронза фрагментируется стриминговыми коммитами. Серебро копит долг удалений через мутации. Золото тратит хранилище на устаревшие снапшоты. Деградация неотделима от append-only транзакционного дизайна — это не баг, который чинится, а сила, которой нужно непрерывно противостоять.

Противостоит ей слой обслуживания: сенсорика структурного здоровья по всем таблицам и каталогам, оценка состояния адаптивными скорингами, планирование последовательного обслуживания с учётом зависимостей, исполнение на движке, достаточно быстром, чтобы работать непрерывно, и обучение на результатах. Плюс умная компакция, сортирующая по реальным паттернам запросов всех движков; маршрутизация, отправляющая каждый запрос в оптимальный движок; декларативные политики, которые работают сами; и управляемый доступ ИИ-агентов с discoverable-схемами, guardrails и лимитами бюджета.

Архитектура работает, потому что кто-то постоянно поддерживает её в рабочем состоянии. Этот «кто-то» — процесс обслуживания, а не удача.