第十四章 数据湖与湖仓一体 - 现代数据架构
导读
在过去十年中,企业数据的规模和多样性呈爆炸式增长。传统的数据仓库虽然提供了强大的查询能力,但在处理海量非结构化数据、支持多种计算引擎、以及成本控制方面面临挑战。与此同时,数据湖以其低成本、灵活性和开放性吸引了大量关注,但在查询性能、事务支持和数据治理方面存在不足。
湖仓一体(Lakehouse)应运而生,它结合了数据湖和数据仓库的优势——在数据湖的低成本开放存储之上,叠加数据仓库的 ACID 事务、高性能查询和数据治理能力。这一架构正在成为现代数据平台的标准范式。
本章将深入探讨数据湖的演进、开放表格式(Apache Iceberg、Apache Hudi、Delta Lake)的技术原理、湖仓一体的架构设计,以及现代数据栈的最佳实践。
核心概念详解
14.1 数据仓库的局限
14.1.1 传统数据仓库
传统数据仓库(如 Teradata、Oracle Exadata、Greenplum)是专为分析工作负载设计的系统。它们通常采用共享存储或共享 nothing 架构,提供强大的 SQL 查询能力和 ACID 事务支持。
传统数据仓库的特点:
- 专有格式:数据以专有的列式格式存储,与特定的计算引擎绑定。
- 紧耦合:计算和存储通常部署在同一组机器上,扩缩容需要同时调整。
- 高成本:需要专用的硬件和软件许可,总体拥有成本高。
- 封闭生态:只能使用厂商提供的工具和接口。
14.1.2 数据仓库面临的挑战
随着数据规模和多样性的增长,传统数据仓库面临以下挑战:
数据规模:
- 数据量从 TB 级增长到 PB 甚至 EB 级。
- 传统数据仓库的扩展成本随规模线性增长。
数据多样性:
- 除了结构化数据,还需要处理半结构化(JSON、XML)和非结构化(图片、视频、文本)数据。
- 传统数据仓库主要针对结构化数据优化。
计算多样性:
- 除了 SQL 查询,还需要支持机器学习、流处理、图计算等多种计算引擎。
- 传统数据仓库通常只支持 SQL。
成本压力:
- 数据量增长但 IT 预算有限。
- 需要更灵活的计费模式(按需付费 vs 预留资源)。
14.2 数据湖的兴起
14.2.1 数据湖的定义
数据湖(Data Lake)是一个集中式的数据存储,可以存储任意规模的结构化、半结构化和非结构化数据。
数据湖的核心特点:
- 开放格式:数据以开放的格式存储(如 Parquet、ORC、CSV、JSON),不依赖特定的计算引擎。
- 低成本存储:通常使用云对象存储(如 S3、GCS、Azure Blob),成本远低于传统数据仓库。
- Schema-on-Read:数据写入时不强制 Schema,读取时才解析数据结构。
- 多引擎支持:同一份数据可以被 SQL 引擎、流处理引擎、机器学习框架等多种计算引擎访问。
14.2.2 数据湖的架构
典型的数据湖架构:
存储层:
- 云对象存储(S3、GCS、Azure Blob)或分布式文件系统(HDFS)。
- 提供低成本、高持久性、高可用的数据存储。
数据格式:
- 列式格式:Parquet、ORC(适合分析查询)。
- 行式格式:CSV、JSON、Avro(适合流处理和灵活 Schema)。
计算层:
- SQL 引擎:Presto/Trino、Spark SQL、Hive。
- 流处理:Spark Streaming、Flink。
- 机器学习:Spark MLlib、TensorFlow、PyTorch。
元数据层:
- 数据目录(Data Catalog):如 AWS Glue、Apache Atlas。
- 提供数据的发现、搜索和治理。
14.2.3 数据湖的问题
虽然数据湖提供了灵活性和低成本,但也引入了新的问题:
缺乏事务支持:
- 原始的数据湖不支持 ACID 事务。
- 并发读写可能导致数据不一致。
- 部分写入失败可能导致脏数据。
数据质量差:
- Schema-on-Read 意味着数据写入时不验证,可能导致"数据沼泽"。
- 缺乏数据验证和治理机制。
查询性能不稳定:
- 没有索引和统计信息优化,查询性能不可预测。
- 小文件问题:大量小文件导致查询性能下降。
缺乏更新和删除:
- 对象存储通常只支持追加写入,不支持原地更新和删除。
- 数据修正(如 GDPR 的"被遗忘权")困难。
14.3 开放表格式
为了解决数据湖的问题,业界开发了多种开放表格式(Open Table Format),在数据湖之上添加 ACID 事务、索引、更新/删除等能力。
14.3.1 Apache Iceberg
Apache Iceberg是 Netflix 开源的表格式,现在是 Apache 顶级项目。
Iceberg 的核心设计:
隐藏分区(Hidden Partitioning):
- 分区策略由表的元数据管理,用户不需要在查询中指定分区条件。
- 查询优化器自动利用分区信息跳过不相关的数据(分区裁剪)。
- 支持按值分区(如按日期)、按桶分区(如按 ID 哈希)。
Schema 演化:
- 支持安全的 Schema 变更:添加列、删除列、重命名列、修改列类型。
- Schema 变更不需要重写数据。
- 通过列 ID(而非列名)追踪列,保证 Schema 演化的安全性。
ACID 事务:
- 使用乐观并发控制,支持并发写入。
- 写入时创建新的快照(Snapshot),读取时选择一个快照。
- 快照之间通过元数据链连接,支持时间旅行。
文件格式:
- 默认使用 Parquet 作为数据文件格式。
- 也支持 ORC 和 Avro。
索引:
- 支持 Min/Max 索引:每个数据文件记录每列的最小值和最大值。
- 查询时根据过滤条件跳过不相关的文件(文件裁剪)。
- 支持 Bloom Filter 索引(实验性)。
14.3.2 Apache Hudi
Apache Hudi(Hadoop Updates and Incrementals)由 Uber 开发,专注于支持高效的更新和增量处理。
Hudi 的核心特性:
两种表类型:
- Copy-on-Write(CoW):写入时重写整个数据文件。读取性能高,写入放大。
- Merge-on-Read(MoR):写入时只写入增量日志,读取时合并基础数据和增量。写入性能高,读取时需要合并。
时间旅行:
- 支持按时间点查询数据。
- 每个提交创建一个新版本,可以回滚到任意版本。
增量查询:
- 支持查询自某个时间点以来的增量数据。
- 适合增量 ETL 和流式消费。
索引:
- 支持 Bloom Filter 索引,加速点查。
- 支持 Record Level Index,加速更新操作。
14.3.3 Delta Lake
Delta Lake由 Databricks 开发,是 Spark 生态系统中的表格式。
Delta Lake 的核心特性:
ACID 事务:
- 使用乐观并发控制。
- 支持 Serializable 隔离级别。
Schema 强制:
- 写入时验证 Schema,防止无效数据写入。
- 支持 Schema 演化(添加列、覆盖 Schema)。
时间旅行:
- 支持按版本号或时间戳查询历史数据。
- 支持数据回滚。
数据清理:
VACUUM命令清理旧版本的数据文件。- 可配置保留时间(默认 7 天)。
统一批处理和流处理:
- Delta 表可以作为批处理的源/目标,也可以作为流处理的源/汇。
- 流处理使用
readStream和writeStreamAPI。
14.3.4 三种格式对比
| 特性 | Iceberg | Hudi | Delta Lake |
|---|---|---|---|
| 更新模式 | CoW | CoW + MoR | CoW |
| 流式写入 | 支持 | 原生支持 | 支持 |
| 增量查询 | 支持 | 原生支持 | 支持 |
| Schema 演化 | 安全 | 支持 | 支持 |
| 时间旅行 | 支持 | 支持 | 支持 |
| 引擎支持 | 多引擎 | Spark 为主 | Spark 为主 |
| 社区 | Apache | Apache | Databricks 主导 |
14.4 湖仓一体架构
14.4.1 湖仓一体的定义
湖仓一体(Lakehouse)是在数据湖的低成本开放存储之上,叠加数据仓库的管理和性能特性的架构。
湖仓一体的核心特征:
- 开放存储:数据以开放格式存储在对象存储中。
- ACID 事务:通过开放表格式提供事务支持。
- 高性能查询:通过索引、缓存、查询优化提供接近数据仓库的查询性能。
- 数据治理:通过数据目录、血缘追踪、访问控制提供治理能力。
- 多引擎支持:同一份数据可以被多种计算引擎访问。
14.4.2 湖仓一体的架构
典型的湖仓一体架构包含以下层:
原始数据层(Bronze / Raw):
- 原始数据直接写入数据湖,保持原始格式。
- 支持数据回溯和审计。
清洗数据层(Silver / Cleaned):
- 对原始数据进行清洗、验证、标准化。
- 使用开放表格式(Iceberg/Hudi/Delta)存储,提供 ACID 事务。
- 支持更新和删除操作。
聚合数据层(Gold / Curated):
- 针对业务查询优化的数据视图。
- 预聚合、预计算的结果。
- 使用列式格式存储,优化查询性能。
计算层:
- SQL 引擎:Trino、Spark SQL。
- 流处理:Flink、Spark Streaming。
- 机器学习:Spark MLlib、Python 生态。
治理层:
- 数据目录:Apache Atlas、AWS Glue、DataHub。
- 数据血缘:追踪数据的来源和转换。
- 访问控制:基于角色的数据访问控制。
14.4.3 湖仓一体的优势
相比纯数据湖或纯数据仓库,湖仓一体具有以下优势:
成本效益:
- 使用低成本的对象存储,存储成本远低于数据仓库。
- 计算和存储分离,可以独立扩展。
- 按需使用计算资源,避免预留成本。
灵活性:
- 支持多种数据格式和计算引擎。
- 数据不被锁定在特定系统中。
- 可以根据需求选择最合适的计算引擎。
可靠性:
- ACID 事务保证数据一致性。
- 时间旅行支持数据回溯和审计。
- Schema 强制保证数据质量。
性能:
- 通过索引、缓存、分区裁剪优化查询性能。
- 列式格式提供高压缩比和向量化执行。
- 接近传统数据仓库的查询性能。
14.5 现代数据栈
14.5.1 数据集成(Data Integration)
现代数据栈的数据集成工具:
ETL 工具:
- Apache Spark:分布式数据处理引擎,支持批处理和流处理。
- Apache Flink:流处理引擎,支持事件驱动的数据处理。
- dbt(Data Build Tool):SQL-first 的数据转换工具,在数据仓库内执行转换。
ELT 工具:
- Fivetran:自动化的数据管道,将 SaaS 数据同步到数据仓库。
- Airbyte:开源的数据集成平台,支持 300+ 数据源。
- Airflow / Dagster / Prefect:工作流编排工具。
CDC 工具:
- Debezium:开源的 CDC 平台,支持多种数据库。
- AWS DMS:AWS 的数据迁移服务。
14.5.2 数据质量与治理
数据质量:
- Great Expectations:开源的数据质量框架。
- Soda:数据质量监控平台。
- Monte Carlo:数据可观测性平台。
数据治理:
- Apache Atlas:开源的数据治理和元数据管理。
- DataHub(LinkedIn):开源的元数据平台。
- Collibra:商业数据治理平台。
数据安全:
- 行级安全(Row-Level Security):根据用户角色控制数据访问。
- 列级安全(Column-Level Security):控制敏感列的访问。
- 数据脱敏:对敏感数据进行脱敏处理。
14.5.3 数据服务(Data as a Service)
现代数据栈趋向于将数据作为服务提供:
数据产品(Data Product):
- 将数据组织为可发现、可信赖、自描述的产品。
- 每个数据产品有明确的 owner、SLA、文档。
- 数据消费者通过标准接口访问数据产品。
数据网格(Data Mesh):
- 去中心化的数据架构,每个业务领域负责自己的数据产品。
- 数据平台团队提供基础设施和标准。
- 领域团队负责数据的质量、治理和服务。
重要知识点
知识点 1:开放表格式的元数据管理
开放表格式的核心是元数据管理。元数据包括:
表元数据:
- 表的 Schema(列名、类型)。
- 分区规范。
- 表属性(如压缩格式、保留策略)。
快照元数据:
- 每个快照记录表的完整状态。
- 包含数据文件列表、统计信息。
- 快照之间通过父指针链接,形成版本历史。
文件元数据:
- 每个数据文件的路径、大小、行数。
- 每列的统计信息(min、max、null count)。
- 分区值。
元数据的存储:
- Iceberg:使用 JSON 或 Avro 格式的元数据文件,存储在对象存储中。
- Hudi:使用 Hoodie 元数据表,存储在对象存储中。
- Delta Lake:使用 JSON 格式的日志文件(_delta_log),存储在对象存储中。
知识点 2:文件布局优化
数据湖中的文件布局对查询性能有重大影响。
小文件问题:
- 大量小文件导致查询时需要打开大量文件,元数据开销大。
- 解决方案:定期合并小文件(Compaction)。
数据倾斜:
- 某些分区的数据量远大于其他分区。
- 解决方案:调整分区策略,使用更细粒度的分区。
Z-Order 排序:
- 将数据按多个列排序,使得相关数据在物理上相邻。
- 查询时可以根据过滤条件跳过不相关的数据块。
- Delta Lake 和 Databricks 支持 Z-Order 优化。
缓存和索引:
- 使用本地 SSD 缓存热数据。
- 使用 Bloom Filter、Min/Max 索引加速过滤。
知识点 3:数据湖的查询引擎
数据湖的查询引擎需要理解开放表格式的元数据:
Trino(Presto):
- 支持 Iceberg、Delta Lake、Hudi 的连接器。
- 提供高性能的交互式查询。
- 支持联邦查询(跨多个数据源)。
Spark SQL:
- 原生支持 Delta Lake,通过连接器支持 Iceberg 和 Hudi。
- 适合大规模批处理和 ETL。
StarRocks / Apache Doris:
- 支持直接查询 Iceberg 表。
- 提供高性能的 OLAP 查询。
Apache Druid:
- 支持从数据湖摄入数据。
- 提供实时分析能力。
知识点 4:数据湖的成本优化
数据湖的成本优化策略:
存储分层:
- 热数据:标准存储(如 S3 Standard)。
- 温数据:低频存储(如 S3 Standard-IA)。
- 冷数据:归档存储(如 S3 Glacier)。
- 使用生命周期策略自动迁移。
数据压缩:
- 使用高效的压缩算法(如 Zstd、Snappy)。
- 列式格式本身提供高压缩比。
数据清理:
- 定期清理过期数据和旧版本。
- 使用 VACUUM 命令清理 Delta Lake 的旧版本。
计算优化:
- 使用 Spot 实例降低计算成本。
- 自动扩缩容,避免闲置资源。
- 查询优化:分区裁剪、文件裁剪、谓词下推。
常见误区
误区 1:"数据湖可以完全替代数据仓库"
纠正:数据湖和数据仓库有不同的适用场景。数据湖适合大规模、多格式的数据存储和多引擎处理;数据仓库适合高性能的 SQL 查询和强一致性保证。湖仓一体结合了两者的优势,但不是简单的替代关系。
误区 2:"开放表格式的性能不如专有数据仓库"
纠正:现代开放表格式(Iceberg、Delta Lake)通过索引、缓存、查询优化,已经可以提供接近专有数据仓库的查询性能。Trino、StarRocks 等引擎对开放表格式的支持越来越好,性能差距在缩小。
误区 3:"数据湖不需要数据治理"
纠正:数据湖的灵活性使得数据治理更加重要。没有治理的数据湖很容易变成"数据沼泽"——数据质量差、难以发现、难以信任。需要数据目录、血缘追踪、Schema 强制、访问控制等治理机制。
误区 4:"所有数据都应该放在数据湖中"
纠正:不是所有数据都适合放在数据湖中。高频访问的热数据、需要强一致性的数据、需要低延迟查询的数据,可能更适合放在专门的数据库或缓存中。数据湖适合存储大规模的历史数据、原始数据和中间数据。
误区 5:"湖仓一体是一种具体的产品"
纠正:湖仓一体是一种架构理念,而非具体的产品。可以通过多种产品组合实现湖仓一体——如 S3 + Iceberg + Trino + dbt + DataHub。选择具体的产品需要根据团队技能、业务需求和生态系统来决定。
实践应用
实践 1:设计湖仓一体架构
设计湖仓一体架构的步骤:
选择存储层:云对象存储(S3、GCS)或 HDFS。
选择表格式:根据引擎支持和团队技能选择 Iceberg、Hudi 或 Delta Lake。
设计数据分层:Bronze(原始)→ Silver(清洗)→ Gold(聚合)。
选择计算引擎:根据查询需求选择 Trino、Spark SQL 等。
设计数据管道:使用 Airflow、dbt 等工具编排 ETL 流程。
实施数据治理:使用数据目录、血缘追踪、访问控制。
实践 2:选择开放表格式
选择开放表格式的决策因素:
| 因素 | Iceberg | Hudi | Delta Lake |
|---|---|---|---|
| 引擎多样性 | 多引擎 | Spark 为主 | Spark 为主 |
| 更新频率 | 中 | 高 | 中 |
| 流式写入 | 支持 | 原生支持 | 支持 |
| 社区活跃度 | 高 | 中 | 高 |
| 学习曲线 | 中 | 中 | 低(Spark 用户) |
实践 3:数据湖性能优化
优化数据湖查询性能的策略:
分区策略:根据查询模式选择合适的分区键和粒度。
文件大小:保持数据文件在 128MB-1GB 之间,避免小文件。
压缩格式:使用 Zstd 或 Snappy 压缩,平衡压缩比和速度。
排序优化:使用 Z-Order 或 Range 排序,加速过滤。
缓存:使用本地 SSD 缓存热数据。
索引:使用 Min/Max 索引和 Bloom Filter 加速过滤。
实践 4:数据湖成本管理
管理数据湖成本的策略:
存储分层:自动将冷数据迁移到低成本存储。
数据保留:设置数据保留策略,定期清理过期数据。
压缩:使用高效压缩减少存储空间。
计算优化:使用 Spot 实例、自动扩缩容。
查询优化:分区裁剪、文件裁剪、谓词下推减少扫描数据量。
监控:监控存储和计算成本,设置预算告警。
本章小结
本章深入探讨了数据湖与湖仓一体的核心概念和实践:
数据仓库的局限:
- 传统数据仓库在规模、多样性、成本和开放性方面面临挑战。
- 需要新的架构来应对现代数据的需求。
数据湖的兴起与问题:
- 数据湖提供低成本、灵活、开放的数据存储。
- 但缺乏事务支持、数据质量差、查询性能不稳定。
开放表格式:
- Iceberg:隐藏分区、安全 Schema 演化、多引擎支持。
- Hudi:高效的更新和增量处理、流式写入。
- Delta Lake:ACID 事务、Schema 强制、时间旅行。
- 在数据湖之上提供事务、索引、更新/删除等能力。
湖仓一体架构:
- 结合数据湖的低成本和数据仓库的管理/性能特性。
- 数据分层:Bronze → Silver → Gold。
- 多引擎支持、开放格式、ACID 事务。
现代数据栈:
- 数据集成:ETL/ELT 工具、CDC 工具。
- 数据治理:数据目录、血缘追踪、访问控制。
- 数据服务:数据产品、数据网格。
湖仓一体正在成为现代数据平台的标准架构。它通过开放表格式在数据湖之上提供数据仓库的能力,兼顾了灵活性、性能和成本。理解数据湖、开放表格式和湖仓一体的概念,对于构建现代化数据平台至关重要。
在选择开放表格式时,需要综合考虑团队的技术栈、引擎兼容性和社区活跃度。如果团队以 Spark 为核心计算引擎,Delta Lake 是一个自然的选择;如果需要多引擎支持(如 Trino、Spark、Flink 同时访问),Apache Iceberg 可能是更好的选择;如果应用场景涉及高频的数据更新和增量处理,Apache Hudi 值得重点考虑。无论选择哪种格式,关键是要确保数据格式的开放性——避免被单一供应商锁定,保持未来切换引擎和工具的灵活性。
湖仓一体的成功实施还需要关注数据治理和组织协作。技术架构只是基础,真正的挑战在于建立清晰的数据所有权、质量标准和服务级别协议。数据平台团队需要提供易用的工具和清晰的文档,降低领域团队发布高质量数据产品的门槛。只有技术和组织双管齐下,湖仓一体才能真正发挥其价值。
从技术选型的角度来看,湖仓一体的实施应该遵循渐进式的策略。不必一开始就追求完美的架构设计,而是从最紧迫的业务需求出发,逐步构建和完善数据平台。例如,可以先将现有的数据仓库数据迁移到开放格式(如 Parquet),建立基础的数据湖存储层;然后引入开放表格式(如 Iceberg),添加事务支持和 Schema 演化能力;最后根据查询需求,逐步引入专门的计算引擎和优化策略。这种渐进式的方法可以降低实施风险,同时在每个阶段都能交付可衡量的业务价值。此外,在迁移过程中应该特别注意保持向后兼容——确保现有的报表和分析工具在架构升级后仍然可以正常工作,避免对业务造成中断。