数据湖架构设计
约 1347 字大约 4 分钟
data-lakearchitecture
2025-09-09
数据湖作为集中式存储库,能以原始格式存储任意规模的结构化与非结构化数据。本文介绍数据湖与数据仓库的区别、湖仓一体架构、存储分层设计、元数据管理以及主流开放表格式的对比。
数据湖 vs 数据仓库
| 维度 | 数据仓库 | 数据湖 |
|---|---|---|
| 数据类型 | 结构化 | 结构化+半结构化+非结构化 |
| Schema | 写入时定义 | 读取时定义 |
| 存储成本 | 高 | 低(对象存储) |
| 数据质量 | 高(经过 ETL 清洗) | 参差不齐 |
| 用户 | 业务分析师 | 数据工程师、数据科学家 |
| 典型方案 | Snowflake, Redshift | S3+Spark, ADLS+Databricks |
| ACID 事务 | 原生支持 | 需要表格式层(Iceberg等) |
湖仓一体(Lakehouse)
Lakehouse 融合数据湖的灵活性与数据仓库的管理能力,是现代数据架构的主流方向。
Lakehouse 的核心特征:
- ACID 事务:通过开放表格式实现
- Schema 强制与演化:支持 schema enforcement 和 schema evolution
- 多引擎访问:Spark、Trino、Flink 等均可读写
- 时间旅行:查询历史版本的数据
- 开放格式:避免厂商锁定
存储分层设计
原始层(Bronze / Raw)
- 存储原始数据的精确副本
- 不做任何转换,保留数据溯源能力
- 按数据源和日期分区
- 保留时间长(通常 1-3 年甚至更久)
治理层(Silver / Curated)
- 数据清洗:去重、空值处理、类型转换
- 数据标准化:统一字段命名、时间格式
- 数据整合:跨源数据关联
- Schema 管理:强制 schema、版本控制
消费层(Gold / Consumption)
- 面向特定业务需求的聚合视图
- 预计算指标和维度表
- ML 特征表
- API 服务层的物化视图
# PySpark 分层处理示例
# === Bronze 层:原样写入 ===
raw_df = spark.read.json("s3://data-lake/raw/events/2025/09/09/")
raw_df.write.format("delta") \
.mode("append") \
.save("s3://data-lake/bronze/events/")
# === Silver 层:清洗转换 ===
bronze_df = spark.read.format("delta").load("s3://data-lake/bronze/events/")
silver_df = (
bronze_df
.dropDuplicates(["event_id"])
.filter(F.col("user_id").isNotNull())
.withColumn("event_time", F.to_timestamp("event_time_str"))
.withColumn("processed_at", F.current_timestamp())
.select("event_id", "user_id", "event_type", "event_time",
"properties", "processed_at")
)
silver_df.write.format("delta") \
.mode("overwrite") \
.partitionBy("event_type") \
.option("overwriteSchema", "true") \
.save("s3://data-lake/silver/events/")
# === Gold 层:业务聚合 ===
silver_events = spark.read.format("delta").load("s3://data-lake/silver/events/")
gold_daily_metrics = (
silver_events
.withColumn("date", F.to_date("event_time"))
.groupBy("date", "event_type")
.agg(
F.countDistinct("user_id").alias("unique_users"),
F.count("event_id").alias("event_count"),
)
)
gold_daily_metrics.write.format("delta") \
.mode("overwrite") \
.save("s3://data-lake/gold/daily_metrics/")元数据目录(Catalog)
元数据目录是数据湖的"目录索引",管理表的位置、Schema、统计信息和访问权限。
| 方案 | 开源/商业 | 特点 |
|---|---|---|
| Hive Metastore | 开源 | 最广泛支持,但功能有限 |
| AWS Glue Catalog | 商业 | AWS 生态集成 |
| Unity Catalog | 商业 | Databricks 统一治理 |
| Apache Polaris | 开源 | Snowflake 开源 Iceberg catalog |
| Nessie | 开源 | Git-like 目录版本控制 |
数据治理(Governance)
开放表格式对比
Apache Iceberg
- Netflix 开源,社区活跃
- 隐藏分区(hidden partitioning):用户无需在查询中显式指定分区
- Partition Evolution:分区策略可在线变更
- Schema Evolution:安全的 schema 变更
Apache Hudi
- Uber 开源
- 擅长 upsert 和增量查询
- 支持 Copy-on-Write (CoW) 和 Merge-on-Read (MoR) 两种表类型
- 内置 compaction 服务
Delta Lake
- Databricks 开源
- 与 Spark 深度集成
- Transaction Log 实现 ACID
- 支持 OPTIMIZE、Z-ordering、VACUUM
| 特性 | Iceberg | Hudi | Delta Lake |
|---|---|---|---|
| 创建者 | Netflix | Uber | Databricks |
| ACID 事务 | 支持 | 支持 | 支持 |
| 时间旅行 | 支持 | 支持 | 支持 |
| Schema Evolution | 强 | 中 | 强 |
| 分区演化 | 隐藏分区 | 不支持 | 不支持 |
| Upsert | 支持 | 原生强项 | 支持 |
| 引擎支持 | 广泛 (Spark/Trino/Flink) | 以 Spark 为主 | Spark 优先 |
| 社区趋势 | 快速增长 | 稳定 | 稳定 |
# Apache Iceberg 使用示例
spark = SparkSession.builder \
.config("spark.sql.catalog.lakehouse", "org.apache.iceberg.spark.SparkCatalog") \
.config("spark.sql.catalog.lakehouse.type", "hadoop") \
.config("spark.sql.catalog.lakehouse.warehouse", "s3://data-lake/iceberg/") \
.getOrCreate()
# 创建表
spark.sql("""
CREATE TABLE lakehouse.db.events (
event_id STRING,
user_id STRING,
event_type STRING,
event_time TIMESTAMP,
properties MAP<STRING, STRING>
)
USING iceberg
PARTITIONED BY (days(event_time))
""")
# 时间旅行查询
spark.sql("SELECT * FROM lakehouse.db.events VERSION AS OF 12345")
spark.sql("SELECT * FROM lakehouse.db.events TIMESTAMP AS OF '2025-09-01 00:00:00'")
# 分区演化
spark.sql("ALTER TABLE lakehouse.db.events ADD PARTITION FIELD hours(event_time)")总结
现代数据湖架构正快速向湖仓一体演进,其核心是开放表格式(Iceberg/Delta/Hudi)+ 对象存储 + 多引擎计算。Bronze/Silver/Gold 分层设计确保数据从原始到可消费的有序转换。元数据目录和数据治理是保障数据湖不退化为"数据沼泽"的关键。Iceberg 因其引擎无关性和隐藏分区等特性,正在成为社区的首选格式。
贡献者
更新日志
2026/3/14 13:09
查看所有更新日志
9f6c2-feat: organize wiki content and refresh site setup于