Перейти к содержанию

Data Lake архитектура

Зачем это DE?

Data Lake — центральное хранилище всех данных организации. Без правильной архитектуры он превращается в Data Swamp (болото). Медальонная архитектура, каталог, governance — то, что отличает рабочий lake от свалки файлов.


Data Lake vs Data Warehouse vs Lakehouse

Параметр Data Warehouse Data Lake Lakehouse
Формат Структурированный (SQL) Любой (raw файлы) Структурированный + raw
Схема Schema-on-Write Schema-on-Read Schema-on-Write (Delta/Iceberg)
Движок PostgreSQL, Greenplum, Redshift Spark, Presto, Athena Spark + Delta Lake / Iceberg
Стоимость $$$ (compute + storage связаны) $ (S3 дёшево) $ (S3 + compute по требованию)
ACID ✅ (Delta/Iceberg)
Governance Встроен Нужен каталог Встроен (Unity Catalog, Nessie)

Медальонная архитектура (Bronze → Silver → Gold)

Text Only
┌─────────────────────────────────────────────────────────────┐
│                     SOURCES                                  │
│  API, Kafka, DB CDC, Files, Logs, IoT                       │
└──────────┬──────────┬──────────┬──────────┬─────────────────┘
           ↓          ↓          ↓          ↓
┌─────────────────────────────────────────────────────────────┐
│  BRONZE (Raw)                                                │
│  • Данные as-is: JSON, CSV, Avro, DB dumps                  │
│  • Append-only, без изменений                                │
│  • Партиционирование по дате загрузки                        │
│  • Хранение: 90-365 дней                                     │
│  • Формат: исходный или Parquet/Delta                        │
└──────────────────────────┬──────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│  SILVER (Cleaned / Conformed)                                │
│  • Дедупликация, валидация, приведение типов                 │
│  • Единая схема (conform), JOIN обогащение                   │
│  • SCD Type 2 для измерений                                  │
│  • Формат: Delta Lake / Iceberg (ACID!)                      │
│  • Хранение: 1-3 года                                        │
└──────────────────────────┬──────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│  GOLD (Business-level / Analytics)                           │
│  • Витрины для конкретных бизнес-задач                       │
│  • Агрегаты, KPI, ML-фичи                                   │
│  • Star Schema для BI                                        │
│  • Формат: Delta Lake / Parquet                              │
│  • Доступ: аналитики, BI-инструменты, ML                    │
└─────────────────────────────────────────────────────────────┘

Принципы каждого слоя

Bronze:

  • Никаких трансформаций — только складываем
  • Добавляем метаданные: _loaded_at, _source, _batch_id
  • Если источник отдаёт JSON — сохраняем JSON
  • Идемпотентность: повторная загрузка не создаёт дублей
Python
# Bronze: сохранить ответ API as-is
raw_data = requests.get("https://api.example.com/orders").json()
df = pd.DataFrame(raw_data)
df["_loaded_at"] = datetime.now()
df["_source"] = "api_orders"
df.to_parquet(f"s3://lake/bronze/orders/dt={today}/data.parquet")

Silver:

  • Дедупликация (ROW_NUMBER по natural key)
  • Приведение типов (string → int, timestamp parsing)
  • Валидация (NULL-проверки, range checks)
  • Обогащение (JOIN с справочниками)
Python
# Silver: очистка
df = pd.read_parquet("s3://lake/bronze/orders/")
df = df.drop_duplicates(subset=["order_id"], keep="last")
df["amount"] = pd.to_numeric(df["amount"], errors="coerce")
df = df.dropna(subset=["order_id", "amount"])
df.to_parquet(f"s3://lake/silver/orders/dt={today}/data.parquet")

Gold:

  • Агрегаты по бизнес-логике
  • Star Schema для BI
  • Предрассчитанные метрики
Python
# Gold: витрина выручки
revenue = (df.groupby(["date", "region"])
             .agg(orders=("order_id", "count"),
                  revenue=("amount", "sum"))
             .reset_index())
revenue.to_parquet("s3://lake/gold/daily_revenue/data.parquet")

Schema-on-Read vs Schema-on-Write

Schema-on-Read (Data Lake)

Данные складываются без схемы. Схема применяется при чтении:

Python
# Читаем CSV — схему определяем при чтении
df = spark.read.csv("s3://lake/raw/messy.csv",
                     header=True, inferSchema=True)
# Проблема: inferSchema может ошибиться (string вместо int)

Плюсы: гибкость, быстрая загрузка Минусы: "мусор на входе — мусор на выходе", каждый потребитель парсит по-своему

Schema-on-Write (DWH, Lakehouse)

Схема определяется при записи:

Python
# Delta Lake — MERGE с проверкой схемы
target.alias("t").merge(
    source.alias("s"),
    "t.order_id = s.order_id"
).whenMatchedUpdate(...).whenNotMatchedInsert(...).execute()
# Ошибка если схемы source и target не совпадают

Плюсы: данные гарантированно чистые Минусы: нужна предварительная подготовка


Каталог данных

Без каталога Data Lake превращается в болото: никто не знает, что лежит в s3://lake/old_data_v2_final_FINAL/.

Что содержит каталог

  • Схема — столбцы, типы, описания
  • Расположение — путь в S3
  • Владелец — кто отвечает за данные
  • Lineage — откуда пришли, куда уходят
  • Качество — SLA, freshness, тесты
  • Доступ — кому разрешено читать/писать

Инструменты

Инструмент Тип Особенности
Hive Metastore Технический каталог Стандарт для Spark/Presto/Trino
AWS Glue Catalog Managed Hive Авто-discovery через Crawlers
DataHub Data Discovery Lineage, governance, search
Unity Catalog Databricks Governance + RBAC + lineage
Apache Nessie Git-like каталог Ветвление данных как Git-ветки

Антипаттерны Data Lake

1. Data Swamp — нет организации

Text Only
❌ s3://company/data/
     old_stuff/
     john_test/
     orders_v2_FINAL.csv
     backup_20231201/

Решение: медальонная архитектура + naming convention + каталог.

2. Small Files Problem

Text Only
❌ 100,000 файлов по 1 KB = медленно (overhead на открытие каждого)
✅ Компактификация: объединять мелкие файлы в ~128-256 MB
Python
# Компактификация через Spark
df = spark.read.parquet("s3://lake/bronze/events/dt=2025-01-15/")
df.coalesce(4).write.parquet("s3://lake/bronze/events_compacted/dt=2025-01-15/")

3. Нет партиционирования

Text Only
❌ s3://lake/orders/all_data.parquet  # 100 GB, читаем целиком
✅ s3://lake/orders/year=2025/month=01/  # читаем только нужный месяц

4. Over-partitioning

Text Only
❌ Партиции по customer_id → миллион партиций → миллион мелких файлов
✅ Партиционировать по дате (year/month/day) — 365 партиций в год

5. Нет ACID → потеря данных

Text Only
❌ Parquet: запись прервалась на середине → битый файл
✅ Delta Lake: ACID-транзакции, atomicity, rollback

Что запомнить

Концепция Ключевое Пример
Bronze Raw, as-is, append-only API-ответы в Parquet
Silver Cleaned, conformed, deduplicated JOIN + дедупликация
Gold Business metrics, Star Schema Витрина выручки
Schema-on-Read Гибкость, но мусор CSV в Data Lake
Schema-on-Write Надёжность, но жёсткость Delta Lake MERGE
Каталог Знание о данных DataHub, Hive Metastore
Партиционирование Быстрый доступ year/month/day

Проверь себя


Источники