Лейкхаус на Apache Iceberg
Озеро вместо DWH
Содержание

Ваши данные живут в двух местах, и оба вас раздражают. 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 держит иерархию файлов метаданных там же, где данные:
- Указатель метаданных (хранится в каталоге) — ссылка на текущую версию таблицы.
- Снапшоты — полное состояние таблицы на момент времени. Каждая запись создаёт новый снапшот.
- Manifest list — каждый снапшот ссылается на список активных манифестов.
- Манифесты — каждый отслеживает пачку файлов данных со статистикой: путь, значения партиций, число строк, min/max по колонкам.
- Файлы данных — собственно 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», а подход, при котором обслуживание становится непрерывным замкнутым процессом: сенсорика состояния таблиц, оценка здоровья, планирование операций в правильном порядке, исполнение и учёт результатов.
Цикл обслуживания любой таблицы — это последовательность из пяти операций, где результат каждой становится входом следующей:
- Протухание снапшотов — удалить снапшоты за пределами политики ретеншена. Это разыменовывает больше не нужные файлы и сужает фронт работ для следующих шагов.
- Удаление orphan-файлов — стереть неразыменованные файлы старше окна безопасности: то, что освободил экспайр, плюс мусор от упавших записей.
- Компакция файлов данных — слить мелкие файлы в оптимальные по размеру, схлопнуть delete-маркеры, чтобы последующие чтения не платили за их применение. Опционально — отсортировать по релевантным колонкам для статистического прунинга.
- Переписывание манифестов — консолидировать дерево манифестов под новую раскладку.
- Пересчёт статистики — обновить 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 плюс озеро».
Внедрение: с чего начать
Полная архитектура не нужна в первый день. Каждый шаг даёт самостоятельную ценность и готовит следующий:
- Начни с Iceberg — выбирай его для всех новых аналитических таблиц. Поддержка экосистемы универсальна, каждый крупный движок читает и пишет формат нативно. Существующие Delta Lake-таблицы интероперабельны через UniForm.
- Подними REST-каталог — это точка координации, её стоит сделать правильно с самого начала. AWS Glue — для управляемой простоты, self-hosted Polaris — для полного контроля, Gravitino — если нужна федерация поверх существующих каталогов.
- Построй слой вливания (бронзу) — CDC из операционных баз через Flink, событийные потоки, пакетные загрузки. Append-only и неизменяемо.
- Построй семантический слой (серебро) — доменное моделирование, дедупликация, контроль качества. Это управляемая правда организации, от которой начинается каждый нижестоящий потребитель.
- Подключи слой обслуживания — как только данные потекли и таблицы накопились, соедини систему обслуживания со своим каталогом. Десять минут, без движения данных и изменения инфраструктуры — и у тебя мгновенная видимость здоровья каждой таблицы. Начни в режиме ручного подтверждения: посмотри, что система рекомендует, прежде чем включать автономное исполнение. Потом включай автопилот и дай замкнутому циклу работать.
- Добавляй специализированные движки — по мере роста нагрузки: Trino для интерактивного SQL, DuckDB для ноутбуков, Snowflake для управляемого BI. REST-каталог делает каждое добавление шагом конфигурации.
- Включай маршрутизацию и доступ агентов — с тремя и более движками определи группы маршрутизации и отдай диспетчеризацию системе. Открой таблицы агентам через 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 и лимитами бюджета.
Архитектура работает, потому что кто-то постоянно поддерживает её в рабочем состоянии. Этот «кто-то» — процесс обслуживания, а не удача.


