Reference Architecture Patterns
Analyze production-grade reference architectures including the Modern Data Lakehouse, Enterprise SQL Data Warehouse, Lambda and Kappa patterns, and multi-platform Data Mesh topologies.
Reference Architecture Patterns
Bottom Line: No single architecture pattern fits all scenarios. This section provides production-grade reference architectures for the most common enterprise data platform use cases, annotated with specific service choices and the reasoning behind them.
12.1 Pattern 1: Modern Data Lakehouse (Databricks-Centric)
Best For: Data engineering + ML-heavy organisations, open format preference, Python-native teams.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β MODERN DATA LAKEHOUSE ARCHITECTURE β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
DATA SOURCES INGEST STORE (Bronze)
ββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ
β Operational β Debezium β MSK / Kafka β Streams β S3 Raw Zone β
β Databases βββββββββββΊβ (Event Stream) ββββββββββΊβ (JSON/Avro) β
β (RDS, Mongo) β ββββββββββββββββββββ ββββββββββ¬βββββββββ
β β β
β SaaS Apps β Fivetran β AWS AppFlow β ββββββββββΌβββββββββ
β (Salesforce βββββββββββΊβ (Batch/Sched.) ββββββββββΊβ Auto Loader β
β HubSpot) β ββββββββββββββββββββ β β Bronze Delta β
β β ββββββββββ¬βββββββββ
β Clickstream β Kinesis β Kinesis Streams β β
β (Web/App) βββββββββββΊβ β Firehose βS3 β β
ββββββββββββββββ ββββββββββββββββββββ β
PROCESS (Databricks)
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β DATABRICKS PLATFORM β
β ββββββββββββββββββββ ββββββββββββββββββββ ββββββββββββββββββββββββ β
β β DLT Pipeline β β Batch Jobs β β ML Workflows β β
β β (BronzeβSilver β β (dbt on β β (MLflow + Feature β β
β β βGold via DLT) β β Databricks) β β Store + AutoML) β β
β βββββββββββ¬βββββββββ ββββββββββ¬βββββββββββ βββββββββββ¬βββββββββββββ β
β β β β β
β βββββββββββΌββββββββββββββββββββΌββββββββββββββββββββββββββΌβββββββββββββ β
β β UNITY CATALOG β β
β β Metastore: Bronze β Silver β Gold β Feature Store β ML Models β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
SERVE
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β SQL Warehouse βββΊ BI Tools (Power BI, Tableau, Looker) β
β Databricks AI Gateway βββΊ LLM-powered apps β
β Model Serving REST API βββΊ Real-time ML predictions β
β Delta Sharing βββΊ External partners / downstream consumers β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Implementation Checklist
# 1. Set up Unity Catalog metastore (one-time, per region)
# - Create storage credential for S3
# - Create external location pointing to your S3 bucket
# - Create catalogs: bronze, silver, gold, ml_prod
# 2. Configure Auto Loader for each source
auto_loader_config = {
"format": "cloudFiles",
"cloudFiles.format": "json", # or avro, parquet, csv
"cloudFiles.schemaLocation": "s3://my-lake/schemas/{table}/",
"cloudFiles.inferColumnTypes": "true",
"cloudFiles.maxFilesPerTrigger": 500
}
# 3. Deploy DLT pipeline for Medallion processing
# (See 05_Data_Ingestion.md for full DLT code)
# 4. Set up Databricks Workflows for orchestration
workflow_config = {
"tasks": [
{"task_key": "ingest", "notebook_task": {"notebook_path": "/pipelines/01_ingest"}},
{"task_key": "transform", "depends_on": [{"task_key": "ingest"}],
"notebook_task": {"notebook_path": "/pipelines/02_transform"}},
{"task_key": "ml_features", "depends_on": [{"task_key": "transform"}],
"notebook_task": {"notebook_path": "/pipelines/03_features"}}
]
}
# 5. Configure model serving endpoint
# (See 07_AI_and_ML.md for model serving code)12.2 Pattern 2: Enterprise SQL Data Warehouse (Snowflake-Centric)
Best For: SQL-dominant analytics, large analyst teams, cross-org data sharing, minimal engineering overhead.
dbt Project Structure for Snowflake
dbt_project/
βββ models/
β βββ staging/ β Stage raw Fivetran/Snowpipe tables
β β βββ stg_orders.sql
β β βββ stg_customers.sql
β β βββ stg_products.sql
β βββ intermediate/ β Complex joins and business logic
β β βββ int_customer_order_history.sql
β β βββ int_product_performance.sql
β βββ marts/ β Final, business-facing models
β βββ finance/
β β βββ fct_revenue.sql
β βββ marketing/
β β βββ dim_customer_segments.sql
β βββ core/
β βββ fct_orders.sql
βββ macros/ β Reusable Jinja macros
βββ tests/ β Data quality tests
β βββ generic/
β βββ singular/
βββ dbt_project.yml
-- Example dbt model: marts/finance/fct_revenue.sql
{{
config(
materialized='incremental',
unique_key='order_id',
incremental_strategy='merge',
cluster_by=['order_date'],
post_hook=[
"{{ grant_select_to_role('fct_revenue', 'ANALYST_FINANCE') }}"
]
)
}}
WITH orders AS (
SELECT * FROM {{ ref('int_customer_order_history') }}
{% if is_incremental() %}
WHERE order_date >= (SELECT MAX(order_date) - INTERVAL '3 days' FROM {{ this }})
{% endif %}
),
exchange_rates AS (
SELECT * FROM {{ ref('stg_exchange_rates') }}
),
final AS (
SELECT
o.order_id,
o.customer_id,
o.region,
o.order_date,
o.revenue AS revenue_local,
o.currency,
o.revenue * er.rate_to_usd AS revenue_usd,
o.product_category,
CURRENT_TIMESTAMP() AS dbt_updated_at
FROM orders o
LEFT JOIN exchange_rates er
ON o.currency = er.currency_code
AND o.order_date = er.rate_date
)
SELECT * FROM final12.3 Pattern 3: Lambda Architecture (Real-Time + Batch)
Best For: Use cases requiring both real-time dashboards AND accurate historical analytics (e.g., fraud detection, operational dashboards).
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β LAMBDA ARCHITECTURE β
β β
β Data Source (e.g., payment events) β
β β β
β βββββββββββΌβββββββββββββββββββββββββββββββββββββββββββ β
β β Amazon MSK / Kinesis β β
β β (Event backbone) β β
β βββββββββββ¬βββββββββββββββββββββββ¬βββββββββββββββββββββ β
β β β β
β SPEED LAYERβ BATCH LAYERβ β
β ββββββββββββΌβββββββββββ βββββββββββββΌβββββββββββββββ β
β β Databricks β β Databricks β β
β β Structured Streaming β β Batch Jobs β β
β β β 30-second windows β β β Full reprocessing β β
β β β Redis / DynamoDB β β β Gold Delta tables β β
β β (low latency) β β (accurate) β β
β ββββββββββββ¬ββββββββββββ βββββββββββββ¬βββββββββββββββ β
β β β β
β ββββββββββββΌβββββββββββββββββββββββββββΌβββββββββββββββ β
β β SERVING LAYER β β
β β Query router: real-time data + historical data β β
β β β Dashboards see merged view β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# Lambda: Speed layer (Structured Streaming β live metrics)
speed_query = (
kafka_stream
.withWatermark("event_timestamp", "1 minute")
.groupBy(
F.window("event_timestamp", "30 seconds"),
"region"
)
.agg(
F.sum("amount").alias("live_revenue"),
F.count("*").alias("live_tx_count")
)
.writeStream
.format("delta")
.outputMode("append")
.option("checkpointLocation", "s3://my-bucket/ckpt/speed/")
.trigger(processingTime="5 seconds")
.toTable("analytics.realtime.revenue_windows_5s")
)
# Lambda: Batch layer (accurate, reprocessable historical data)
from pyspark.sql import SparkSession
def run_batch_reprocess(date: str):
"""Run daily batch to correct any speed layer approximations."""
daily_data = spark.table("ecommerce_prod.bronze.payment_events") \
.filter(F.col("event_date") == date)
accurate_aggregates = daily_data.groupBy("region", "event_date") \
.agg(
F.sum("amount").alias("total_revenue"),
F.countDistinct("customer_id").alias("unique_customers"),
F.count("*").alias("transaction_count")
)
accurate_aggregates.write \
.format("delta") \
.mode("overwrite") \
.option("replaceWhere", f"event_date = '{date}'") \
.saveAsTable("analytics.gold.daily_revenue_accurate")12.4 Pattern 4: Kappa Architecture (Stream-Only)
Best For: When batch and stream processing can be unified (modern preferred approach). Databricks Structured Streaming handles both.
12.5 Pattern 5: Hybrid Multi-Platform (Best-of-Breed)
Best For: Large enterprises, 100+ engineers, complex workload mix, ML + BI + sharing all critical.
Data Flow: Databricks β Snowflake (Production Pattern)
# Option 1: Write Gold Delta tables to S3, Snowpipe loads into Snowflake
# (Recommended for decoupling)
# Step 1: Databricks writes Gold table to S3 as Parquet
(
gold_df.write
.format("parquet")
.mode("overwrite")
.partitionBy("order_date")
.save("s3://my-lake/snowflake-landing/gold/orders/")
)
# Step 2: Snowpipe (configured with SQS auto-ingest) picks up new files automatically
# (See 05_Data_Ingestion.md for Snowpipe setup)
# Option 2: Use Spark Snowflake Connector (direct write, simpler)
(
gold_df.write
.format("snowflake")
.option("sfURL", "myorg-myaccount.snowflakecomputing.com")
.option("sfDatabase", "ECOMMERCE")
.option("sfSchema", "GOLD")
.option("sfWarehouse", "LOADER_WH")
.option("dbtable", "ORDERS_DAILY")
.option("private_key_file", "/path/to/rsa_key.p8")
.mode("overwrite")
.save()
)
# β οΈ Direct connector is simpler but creates tight coupling
# β οΈ Snowflake bills for compute on the receiving COPY operation12.6 Pattern 6: Data Mesh with Shared Infrastructure
Best For: Large organisations (>500 engineers), multiple independent domains, federated governance.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β DATA MESH TOPOLOGY β
β β
β ββββββββββββββββββββ ββββββββββββββββββββ ββββββββββββββββββββ β
β β DOMAIN: Finance β β DOMAIN: Marketingβ β DOMAIN: Ops β β
β β β β β β β β
β β Own: Tables, β β Own: Tables, β β Own: Tables, β β
β β Pipelines, SLAs β β Pipelines, SLAs β β Pipelines, SLAs β β
β β β β β β β β
β β Catalog: UC β β Catalog: UC β β Catalog: UC β β
β β (finance.*) β β (marketing.*) β β (ops.*) β β
β ββββββββββββββββββββ ββββββββββββββββββββ ββββββββββββββββββββ β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β SHARED INFRASTRUCTURE PLANE β β
β β β β
β β Unity Catalog Metastore (central governance, federated access) β β
β β S3 Data Lake (shared storage, domain-prefix namespacing) β
β β Databricks Platform (shared compute, domain-isolated workspace) β
β β MSK / Kinesis (shared event bus) β β
β β Snowflake (shared serving layer, cross-domain BI)β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Unity Catalog Multi-Domain Setup
-- Central platform team sets up metastore and top-level catalogs
-- Domain teams own their catalogs
-- Finance domain catalog
CREATE CATALOG finance_prod;
ALTER CATALOG finance_prod SET OWNER TO `finance-data-team@company.com`;
GRANT USE CATALOG ON CATALOG finance_prod TO `finance-data-team@company.com`;
GRANT CREATE SCHEMA ON CATALOG finance_prod TO `finance-data-team@company.com`;
-- Marketing domain catalog
CREATE CATALOG marketing_prod;
ALTER CATALOG marketing_prod SET OWNER TO `marketing-data-team@company.com`;
-- Cross-domain access (controlled, explicit grants)
-- Marketing team needs Finance's revenue data (approved cross-domain use)
GRANT SELECT ON TABLE finance_prod.gold.revenue_by_customer
TO `marketing-data-team@company.com`;
-- Shared "platform" catalog for cross-domain reference data
CREATE CATALOG shared_platform;
GRANT SELECT ON ALL TABLES IN CATALOG shared_platform
TO `all-data-teams@company.com`;12.7 Architecture Anti-Patterns to Avoid
β ANTI-PATTERN 1: Using Snowflake as your primary ETL engine
Snowflake VWs billed per credit-hour = expensive for heavy Spark-equivalent transforms
β Use Databricks or Glue for transformation, Snowflake for serving
β ANTI-PATTERN 2: Running all workloads on one large Redshift cluster
A single large provisioned cluster cannot optimally serve BI + ETL + ML simultaneously
β Isolate workloads with Redshift Serverless or separate clusters
β ANTI-PATTERN 3: All-Purpose Databricks clusters for production pipelines
All-Purpose clusters cost 2x more than Job clusters
β Always use Job clusters for scheduled pipelines
β ANTI-PATTERN 4: S3 with CSV files and no partitioning
Athena at $5/TB scanned on 10TB CSV = $50/query
β Convert to Parquet, partition by date, add file compression
β ANTI-PATTERN 5: Snowflake Time Travel on every table for 90 days
90-day Time Travel on a table with heavy updates = 3-5x storage multiplication
β Tune Time Travel per table: 1 day for staging tables, 90 days for critical facts
β ANTI-PATTERN 6: Building ML models directly in Snowflake SQL
Snowflake Cortex ML Functions are good for simple regression/classification
But complex feature engineering on 100M+ rows needs Spark (Databricks)
β ANTI-PATTERN 7: Ignoring the Glue Catalog
Building AWS data lakes without registering tables in Glue Catalog means
Athena, EMR, Redshift Spectrum cannot discover or join your data
β Always register all datasets in Glue Catalog from day 1
β ANTI-PATTERN 8: Point-to-point platform integrations without event bus
Direct RDS β Redshift, direct CRM β Snowflake without a central event bus
creates a brittle, unobservable architecture
β Route all events through MSK or Kinesis as the single source of truth
12.8 Quick Reference: Service Equivalence Map
| Capability | AWS | Snowflake | Databricks |
|---|---|---|---|
| Object Storage | S3 | S3/GCS/ADLS (managed) | S3/GCS/ADLS (customer) |
| SQL Warehouse | Redshift | Virtual Warehouse | SQL Warehouse |
| Ad-hoc SQL | Athena | Snowsight + VW | SQL Warehouse |
| ETL/ELT Jobs | Glue ETL | Snowpark, dbt | Databricks Jobs, dbt |
| Stream Processing | Kinesis Analytics, MSK | β (Tasks = micro-batch) | Structured Streaming |
| Metadata Catalog | Glue Data Catalog | Snowflake native | Unity Catalog |
| Governance | Lake Formation | Native policies | Unity Catalog |
| Orchestration | MWAA (Airflow), Step Functions | Tasks + DAGs | Databricks Workflows |
| Notebooks | SageMaker Studio | Snowflake Notebooks | Databricks Notebooks |
| ML Training | SageMaker Training | Snowpark ML | MLflow + Spark |
| LLM Integration | Bedrock | Cortex | Mosaic AI / AI Gateway |
| Data Sharing | Data Exchange, Redshift Sharing | Data Sharing, Marketplace | Delta Sharing |
| CI/CD Integration | CodePipeline, GitHub Actions | SchemaChange, dbt Cloud | Databricks Asset Bundles |
| Monitoring | CloudWatch | ACCOUNT_USAGE | Databricks Observability |