Learning Platform
Глоссарий Troubleshooting
Урок 08.03 · 22 мин
Начальный
layersstagingcoremartsmedallionbronze-silver-gold

Зачем слои

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

Простая аналогия: представь завод. Сырьё поступает на склад (raw). Потом проходит обработку — отделяется мусор, проверяется качество (staging). Потом идёт по производственной цепочке (transformations). На выходе — готовая продукция в магазин (marts). Если завод проектировать как “сырьё сразу в магазин” — получится хаос.

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

Классическая четырёхслойная архитектура

Четыре слоя DWH

От источников до BI через staging, core, marts

Source / Raw: данные как пришли из источников. JSON dumps, CSV exports, CDC streams. Сохраняются для history, debug, recovery. Никаких transformations
Staging: первая чистка. Парсинг JSON в колонки, унификация типов (даты, числа), фильтрация мусора, deduplication. Минимальные transformations, ближе к source структуре
Core / Integration: business logic. Объединение источников, conformed dimensions, surrogate keys, SCD Type 2 для истории. Single source of truth для downstream
Marts: domain-specific dimensional models. Star schemas для каждого business domain (sales, marketing, finance). Оптимизированы под BI и аналитику
Presentation / Reporting: pre-aggregated tables для дашбордов. Maximum performance, минимум объёма. Что видят BI tools

Разберём каждый слой подробно.

Layer 0: Source / Raw

Это сырые данные из источников, как они пришли. JSON-дампы из API, CSV экспорты, change-data-capture stream из Postgres.

-- В Snowflake: raw layer хранит JSON как VARIANT
CREATE TABLE raw.stripe_charges (
  loaded_at TIMESTAMP,
  source TEXT,
  data VARIANT  -- весь JSON payload
);

Зачем хранить сырые данные:

  1. Debug. Если что-то сломалось в downstream — есть к чему откатиться.
  2. History. Источник может изменить схему — у нас остаётся история до изменения.
  3. Recovery. Можно пересобрать все downstream слои из raw, если найдена ошибка в логике.
  4. Регуляторика. Часто требуется хранить исходные данные за N лет.

В современной архитектуре raw часто живёт в data lake (Parquet на S3), а не в самом DWH. Это дешевле — long-term storage в S3 стоит в десятки раз меньше, чем в Snowflake. Подробно — модуль 14.

Layer 1: Staging

В staging данные очищаются и типизируются, но структура остаётся близкой к source. То есть в staging-таблицах те же сущности, что в source, но:

  • Парсятся JSON-поля в колонки.
  • Типы приводятся к нормальным (string -> date, string -> number).
  • Применяется deduplication.
  • Фильтруется явный мусор (NULL keys, тестовые записи).
  • Унифицируются форматы (timestamps в UTC, currency codes в ISO).
-- Staging: парсинг JSON в structured колонки
CREATE TABLE staging.stripe_charges AS
SELECT
  data:id::TEXT AS charge_id,
  data:amount::INTEGER / 100 AS amount,
  data:currency::TEXT AS currency,
  data:customer::TEXT AS customer_id,
  TO_TIMESTAMP(data:created::INTEGER) AS created_at,
  data:status::TEXT AS status,
  loaded_at
FROM raw.stripe_charges
WHERE data:id IS NOT NULL;

Важно: staging не делает business logic — никаких JOIN-ов между источниками, никаких aggregations. Только чистка одной сущности. Это позволяет staging моделям быть простыми и независимыми.

Layer 2: Core / Integration

Здесь живёт бизнес-логика и интеграция источников. Происходят:

  • JOIN-ы между источниками (Postgres + Stripe + Salesforce).
  • Создание conformed dimensions (унифицированный dim_customer из всех источников).
  • Surrogate keys для будущих fact-таблиц.
  • SCD Type 2 для исторических dimensions (модуль 8).
  • Бизнес-правила: “клиент с >$1000 покупок = premium”, “категория продукта = по первому слову названия”.
-- Core: интеграция customer из Postgres и Salesforce
CREATE TABLE core.dim_customer AS
WITH unified AS (
  SELECT
    pg.customer_id AS source_id,
    'postgres' AS source_system,
    pg.email,
    pg.name,
    pg.country,
    pg.signup_date
  FROM staging.pg_customers pg
  UNION ALL
  SELECT
    sf.account_id AS source_id,
    'salesforce' AS source_system,
    sf.email,
    sf.account_name AS name,
    sf.billing_country AS country,
    sf.created_date AS signup_date
  FROM staging.sf_accounts sf
),
dedup AS (
  SELECT
    *,
    ROW_NUMBER() OVER (PARTITION BY email ORDER BY signup_date) AS rn
  FROM unified
)
SELECT
  ROW_NUMBER() OVER () AS customer_key,  -- surrogate
  email,
  name,
  country,
  signup_date,
  source_system,
  source_id
FROM dedup
WHERE rn = 1;

Это single source of truth. Все downstream marts ссылаются на core.dim_customer, а не на staging-таблицы.

Layer 3: Marts

В marts строятся dimensional models для конкретных бизнес-доменов. Один mart — один домен (sales, marketing, finance, product analytics).

-- Marts: sales fact table
CREATE TABLE marts.sales.fact_orders AS
SELECT
  o.order_id AS order_key,
  c.customer_key,
  p.product_key,
  d.date_key,
  o.qty,
  o.unit_price,
  o.qty * o.unit_price AS total_amount,
  o.discount_amount,
  o.qty * o.unit_price - o.discount_amount AS net_amount
FROM staging.orders o
JOIN core.dim_customer c ON o.customer_id = c.source_id
JOIN core.dim_product p ON o.product_id = p.source_id
JOIN core.dim_date d ON o.order_date = d.full_date;

Каждый mart — это star schema или OBT, оптимизированный под reads. Аналитики подключают BI tools к marts.

Layer 4: Presentation (опционально)

Для критичных дашбордов с tight latency requirements может строиться дополнительный слой aggregations:

-- Presentation: ежедневная агрегация для дашборда
CREATE TABLE presentation.daily_sales_by_country AS
SELECT
  d.full_date,
  c.country,
  SUM(f.net_amount) AS revenue,
  COUNT(DISTINCT f.customer_key) AS unique_customers,
  COUNT(*) AS orders_count
FROM marts.sales.fact_orders f
JOIN marts.sales.dim_customer c ON f.customer_key = c.customer_key
JOIN marts.sales.dim_date d ON f.date_key = d.date_key
GROUP BY 1, 2;

Это даёт sub-second отклик для дашбордов. Цена — дублирование данных и риск рассинхронизации с marts. Используется только при чётком latency SLA.

Medallion архитектура в lakehouse

В мире lakehouse (Databricks, Iceberg, Delta Lake) появилась терминология bronze/silver/gold. Это та же концепция слоёв, но с другим neimingом и lake-flavored.

Medallion: bronze/silver/gold

Lake-native terminology для тех же слоёв

Bronze: raw данные как пришли. Parquet/JSON на S3, минимум transformations. Это lake-эквивалент Layer 0 (Raw)
Silver: cleaned, conformed данные. Типизированы, дедуплицированы, унифицированы. Эквивалент Staging + Core. Готовы для широкого consumption
Gold: business-level aggregations, готовые для BI. Эквивалент Marts + Presentation. Star schemas, pre-aggregations, KPI
Classical DWH layerMedallion
Raw / SourceBronze
StagingSilver (lower)
Core / IntegrationSilver (upper)
MartsGold
PresentationGold (aggregated)

Это те же концепции, переименованные для lake/lakehouse контекста. Если ты увидел “bronze/silver/gold” в Databricks-документации — знай, что это про layering. Используется в любом современном data pipeline.

Орchestrация слоёв

Слои нужно строить в правильном порядке: staging -> core -> marts. И поддерживать: при изменении источника пересчитать staging, потом core, потом marts.

В современной архитектуре это делает dbt (модуль 13). Каждый слой — это set of SQL models, dbt автоматически вычисляет зависимости и запускает в правильном порядке.

dbt: как ref() строит граф зависимостей между слоями
# dbt project: models/
staging/
  stg_pg_customers.sql       # SELECT FROM raw.pg_customers
  stg_stripe_charges.sql     # SELECT FROM raw.stripe_charges
core/
  dim_customer.sql            # uses staging tables
  dim_product.sql
  dim_date.sql
marts/
  sales/
    fact_orders.sql           # uses core tables

dbt run запустит staging -> core -> marts -> presentation в правильной последовательности.

Реальный пример: e-commerce полный pipeline

Полная картина для нашего e-commerce примера:

Sources:
  Postgres (orders, customers, products)
  Stripe (payments)
  Mailchimp (campaigns)
  Salesforce (B2B accounts)

Raw (Bronze):
  raw.pg_orders        # JSON dumps from Debezium CDC
  raw.stripe_charges
  raw.mailchimp_campaigns
  raw.sf_accounts

Staging (Silver lower):
  staging.orders        # parsed, typed, deduplicated
  staging.charges
  staging.campaigns
  staging.sf_accounts

Core (Silver upper):
  core.dim_customer     # unified Postgres + Salesforce
  core.dim_product      # с category hierarchy inline
  core.dim_date         # календарь компании
  core.fact_orders      # combined orders + payments + items

Marts (Gold):
  marts.sales.fact_orders   # для sales analytics
  marts.sales.dim_*
  marts.marketing.fact_campaigns   # для marketing
  marts.marketing.dim_*

Presentation (Gold aggregated):
  daily_sales_by_country
  monthly_cohort_retention
  campaign_attribution

BI tools (Tableau, Looker, Metabase)

Это стандартная архитектура Modern Data Stack 2026. Каждый слой — material тable в Snowflake/BigQuery/Databricks. dbt управляет.

TIP

Для junior data engineer: запоминать четыре слоя как мнемонику. Любой data pipeline проходит через них. Понимание этой архитектуры — это 50% работы DE.

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

Антипаттерн 1: один слой “transformed”. Команда пишет один большой SQL: source -> final mart. При изменении логики нужно переписать всё. Невозможно понять, где ошибка. Решение — выделить слои.

Антипаттерн 2: business logic в staging. Staging выполняет JOIN-ы и aggregations. Когда нужно создать новый mart с другой логикой — приходится переписывать staging. Решение — staging не делает business logic.

Антипаттерн 3: дублирование между marts. Sales mart и marketing mart строят свой dim_customer отдельно. Со временем расходятся. Решение — conformed dimensions в core layer.

Антипаттерн 4: нет raw layer. Данные сразу loadятся в staging с трансформацией. При ошибке некуда откатиться. Решение — всегда сохранять source как есть.

Попробуй сам

  1. Возьми любой публичный pipeline (например, dbt-jaffle-shop на GitHub). Посмотри models/ — найди staging/, marts/. Запусти dbt run, посмотри dependency graph.
  2. Спроектируй слои для гипотетической задачи: блог-платформа (posts, authors, comments, page views). Какие raw, staging, core, marts таблицы будут?
  3. Реализуй мини-pipeline на DuckDB: возьми 2-3 CSV-источника, напиши SQL для каждого слоя (staging -> core -> mart). Сохраняй в Parquet каждый слой.
  4. Изучи Medallion в Databricks documentation. Сравни с классическими слоями — увидишь, это то же.
Проверка знанийKnowledge check
Архитектор предлагает упростить: 'Зачем нам 4 слоя? Это complexity. Давайте сразу из raw в final mart, одной transformation. Так быстрее'. Какие 3-4 проблемы такого подхода и почему слои важны на масштабе?
ОтветAnswer
Без слоёв возникают системные проблемы. 1) При изменении source — нужно переписать всю transformation chain. С слоями: пересчитать только staging, остальное работает. 2) Когда несколько marts (sales, marketing, finance) — без core layer каждый mart дублирует customer/product logic. Со временем dim_customer в sales и в marketing расходятся, появляются inconsistencies. 3) Debug: ошибка в финальном отчёте — где смотреть? Без слоёв — везде. Со слоями — идти от mart к core к staging к raw, локализуя проблему. 4) Тестирование: каждый слой можно тестировать независимо. 5) Multiple consumers: BI tools, ML pipelines, ad-hoc analytics все используют core/marts, не staging. Без слоёв каждый consumer пишет свою logic. Слои — это инженерная декомпозиция, separation of concerns. На масштабе экономят месяцы работы.

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

Результат: 0 из 0
Концептуальный
Вопрос 1 из 5. Какие 4 классических слоя в архитектуре DWH и что в каждом происходит?

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

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

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

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