什么是三角洲仓库?
三角洲仓库(Delta Warehouse)并非指一个实体建筑,而是一种构建在分布式文件存储系统(如云存储S3、ADLS Gen2、GCS等)之上的数据架构和存储格式。它结合了传统数据仓库的结构化、事务性优点与数据湖的灵活性、可扩展性。
更具体地说,三角洲仓库通常是基于 Delta Lake 开放格式构建的。Delta Lake 为存储在数据湖中的数据带来了 ACID(原子性、一致性、隔离性、持久性)事务能力。这意味着即使是存储在廉价、可扩展的对象存储上的文件数据,也能像传统数据库表一样进行可靠的操作。
三角洲仓库的核心特点
- ACID 事务支持:这是最核心的特性,保证了数据写入和读取的可靠性,避免了数据湖中常见的读写冲突和数据不一致问题。
- Schema Enforcement (模式强制):在写入数据时,Delta Lake 会强制检查数据的模式(schema)是否与表定义一致,防止写入错误或不符合预期的数据,提高数据质量。
- Schema Evolution (模式演进):允许用户以受控的方式更改表的模式,例如添加新列,而无需重写现有数据文件。这为适应不断变化的数据源提供了灵活性。
- 支持 Update/Delete/Merge 操作:可以直接对数据湖中的数据进行更新、删除和合并操作,这在传统数据湖中是非常困难且低效的。
- 数据版本控制和时间旅行:每一次写入操作都会生成一个新的版本,用户可以查询数据的历史版本,或回滚到之前的状态,便于审计、重现和错误恢复。
- 优化读写性能:通过文件小型化合并(Compaction)、数据跳过(Data Skipping)基于统计信息、Z-ordering(数据聚簇)等技术,显著提升大数据查询效率。
三角洲仓库与传统数据仓库、数据湖的关系
三角洲仓库可以被看作是数据湖的增强版,或者说是一种“数据湖屋”(Data Lakehouse)的实现方式。
- vs. 传统数据仓库:传统数仓通常采用专有格式和紧耦合的存储计算架构,扩展成本高,处理半结构化/非结构化数据能力弱。三角洲仓库基于开放格式和云存储,成本效益更高,能轻松处理多种数据类型,并分离存储与计算。
- vs. 数据湖:纯粹的数据湖(如基于Parquet/ORC文件的裸存储)缺乏事务、模式治理、高效更新删除等能力,往往只适用于存储原始数据。三角洲仓库在其之上增加了这些能力,使其可以直接支持 BI、分析和机器学习工作负载,无需将数据 ETL 到单独的数据仓库中。
为什么选择三角洲仓库?
选择三角洲仓库通常是为了解决在处理大规模数据时遇到的挑战,并期望获得更好的数据可靠性、性能和灵活性。
解决的核心问题
- 数据可靠性差:在传统数据湖中,并发读写操作可能导致数据不一致、部分写入失败等问题。三角洲仓库的ACID事务解决了这个问题。
- 难以处理数据变更:GDPR、CCPA等法规要求能够更新或删除特定用户数据,这在纯数据湖上非常困难。三角洲仓库的Update/Delete/Merge功能使其成为可能。
- 数据质量难以保障:缺乏模式强制和事务支持,容易写入脏数据或不符合模式的数据。三角洲仓库通过模式强制提升了数据质量。
- 性能瓶颈:随着数据量增长,纯数据湖的查询性能可能下降。三角洲仓库通过多种优化技术提高了查询效率。
- 架构复杂性:为了弥补纯数据湖的不足,可能需要构建复杂的ETL管道将数据导入到数据仓库,维护成本高。三角洲仓库允许在一个平台上处理多种工作负载,简化了架构。
带来的核心优势
- 简化数据架构:将原始存储(数据湖)直接升级为可信、高性能的存储层,减少或消除对传统数据仓库的依赖,实现“数据湖屋”架构。
- 提升数据分析效率:更快、更可靠的数据使得BI、报表和即席查询更加高效。
- 加速数据科学与机器学习:数据科学家可以直接在经过治理和优化的数据上工作,无需等待数据导入到其他平台。
- 降低总体拥有成本:利用廉价的云对象存储,并通过开放格式避免厂商锁定,通常比传统数据仓库更具成本效益。
- 支持实时分析:Delta Lake支持流式数据写入,可以将流数据直接落地到三角洲仓库,并进行近实时的查询。
三角洲仓库部署在哪里?
三角洲仓库的物理数据文件(Parquet格式)和事务日志(JSON/Parquet格式)都存储在分布式文件系统或对象存储上。
典型的存储位置
-
云对象存储:
- Amazon S3 (Simple Storage Service)
- Azure Data Lake Storage Gen2 (ADLS Gen2)
- Google Cloud Storage (GCS)
- 本地分布式文件系统:HDFS (Hadoop Distributed File System) – 在本地部署或私有云环境中。
选择云对象存储是最常见的方式,因为它提供了极高的可扩展性、可用性和成本效益。三角洲仓库的“表”本质上是对象存储上的一个文件夹,其中包含数据文件和一个名为 `_delta_log` 的子文件夹,用于存放事务日志。
哪些平台和计算引擎支持三角洲仓库?
Delta Lake 是一个开放项目,因此许多大数据处理引擎和平台都提供了对其的支持,允许你“在原地”查询和操作存储在对象存储上的三角洲仓库数据。
-
主要平台:
- Databricks(Delta Lake 的主要贡献者,提供优化的支持)
- Apache Spark(原生支持 Delta Lake connector)
- Trino (原 PrestoSQL)
- PrestoDB
- Apache Hive
- Apache Flink (用于流处理)
- Dremio
- 甚至一些传统数据仓库(如 Snowflake、Redshift)通过外部表或 Spectrum 等功能也提供了有限的支持,可以直接查询 Delta 表。
在企业数据架构中,三角洲仓库通常位于数据湖的精炼层(Refined/Curated Layer)或金牌层(Gold Layer),它存储了经过清洗、转换、聚合并具备良好模式和质量保证的数据,是数据分析师、BI工具、数据科学家和下游应用主要消费的数据源。原始数据可能先存放在数据湖的原始层或银牌层(通常是未经处理或简单处理的Parquet/ORC文件),然后通过 ETL/ELT 过程加载到三角洲仓库。
三角洲仓库如何工作?
三角洲仓库的核心机制在于其如何管理数据文件和元数据,特别是通过一个事务日志来实现可靠的操作。
事务日志(Transaction Log)
每个 Delta Lake 表都有一个与之关联的事务日志,存储在表根目录下名为 `_delta_log` 的子文件夹中。
- 日志是按顺序编号的 JSON 文件列表(例如,00000000000000000000.json, 00000000000000000001.json 等)。
-
每个 JSON 文件代表一个原子提交,记录了对表状态的所有更改:
- 添加了哪些新的数据文件 (`add` action)。
- 移除了哪些旧的数据文件 (`remove` action)。
- 模式的改变 (`metaData` action)。
- 表属性的改变 (`protocol` action)。
- 最新的状态是通过重放从起始到最新提交的所有有效操作来确定的。
ACID 特性实现:
- 原子性 (Atomicity):每个提交要么完全成功,要么完全失败。事务日志的写入过程是原子的,只有日志文件被完全写入并对存储可见,提交才算成功。
- 一致性 (Consistency):读取器在特定提交或时间点看到的数据状态是一致的,不会看到部分完成的写入。写操作会创建一个新的版本,读取器在写操作完成前读的是旧版本。
- 隔离性 (Isolation):写入者在进行更改时,读取者不会受到影响(默认是快照隔离)。读取者继续读取旧版本的数据,直到写入完成并生成新版本。
- 持久性 (Durability):数据文件和日志都存储在持久化的存储系统(如云对象存储)上,一旦写入成功,数据不会丢失。
数据版本控制和时间旅行(Versioning & Time Travel)
事务日志的顺序性使得每个提交都对应一个唯一的版本号。通过指定版本号或时间戳,用户可以查询表的历史快照,实现时间旅行。例如,可以查看表在昨天下午3点的状态。
模式强制与演进(Schema Enforcement & Evolution):
- 强制:写入新数据时,Delta Lake 会比较写入数据的模式与表的当前模式。如果模式不兼容(例如,数据类型不匹配、缺少非空列等),写入操作将失败,防止脏数据。
- 演进:如果只是简单地添加新列,Delta Lake 支持自动模式演进。可以通过配置或特定命令允许模式更改,而无需手动重写整个表。
性能优化技术
- 数据跳过(Data Skipping):Delta Lake 在事务日志中记录了每个数据文件的一些统计信息(如每列的最小值/最大值)。查询引擎可以利用这些信息快速跳过不包含相关数据的物理文件,减少I/O。
- Z-ordering(数据聚簇):对于经常一起查询的列,可以使用 `OPTIMIZE … ZORDER BY (…)` 命令对数据文件进行物理排序。Z-ordering 是一种多维度聚簇技术,能将具有相似值的行物理上存储在一起,极大地加速基于这些列的过滤查询。
- 文件合并(Compaction):频繁的小批量写入会产生大量小文件,这会增加文件元数据开销并降低读性能。使用 `OPTIMIZE` 命令可以将这些小文件合并成更大的文件,提高读取效率。
- 文件清理(Vacuum):时间旅行功能需要保留旧版本的数据文件。`VACUUM` 命令可以基于设定的保留策略,物理删除不再被任何活动事务或保留策略内的旧版本引用的数据文件,从而释放存储空间。
如何使用三角洲仓库?
使用三角洲仓库涉及创建表、加载数据、查询、更新删除以及日常维护操作。这些操作通常通过支持 Delta Lake 的计算引擎(如 Spark、Trino 等)执行,使用标准的 SQL 或相应的 API。
开始构建和使用
- 配置环境:确保你使用的计算引擎已配置好访问你的云对象存储,并集成了 Delta Lake 连接器(如果需要)。
-
创建 Delta 表:你可以指向对象存储上的一个新文件夹,并定义表的模式来创建 Delta 表。例如,在 Spark SQL 中:
CREATE TABLE my_delta_table (id INT, name STRING) USING DELTA LOCATION 's3://my-bucket/delta/my_table';或者,你可以将现有的 Parquet/ORC 文件转换为 Delta 表。
-
加载数据(写入):
-
批量写入:使用 `INSERT INTO` 命令将数据追加到表中。例如:
INSERT INTO my_delta_table VALUES (1, 'Alice');或者从另一个表/数据源加载。
-
合并数据 (Upsert):使用 `MERGE INTO` 命令进行插入、更新或删除操作,非常适合处理缓慢变化维度(SCD)或增量数据加载:
MERGE INTO my_delta_table AS target
USING source_data AS source
ON target.id = source.id
WHEN MATCHED THEN UPDATE SET target.name = source.name
WHEN NOT MATCHED THEN INSERT (id, name) VALUES (source.id, source.name); - 流式写入:使用 Spark Structured Streaming 等框架直接将流数据连续写入 Delta 表,实现低延迟的数据摄入。
-
批量写入:使用 `INSERT INTO` 命令将数据追加到表中。例如:
-
查询数据(读取):使用标准的 SQL `SELECT` 语句查询 Delta 表,就像查询任何其他数据库表一样。计算引擎会自动利用 Delta Lake 的优化特性。
SELECT * FROM my_delta_table WHERE id = 1;要进行时间旅行查询,可以指定版本或时间戳:
SELECT * FROM my_delta_table VERSION AS OF 5;SELECT * FROM my_delta_table TIMESTAMP AS OF '2023-01-01'; -
更新和删除数据:直接使用标准的 SQL `UPDATE` 和 `DELETE` 命令。Delta Lake 会在底层通过标记旧文件为逻辑删除,并写入包含更新数据的新文件来实现这些操作。
UPDATE my_delta_table SET name = 'Bob' WHERE id = 1;DELETE FROM my_delta_table WHERE id = 2;
日常维护操作
-
优化(OPTIMIZE):定期运行 `OPTIMIZE` 命令来合并小文件,并根据需要进行 Z-ordering,以提高查询性能。
OPTIMIZE my_delta_table;OPTIMIZE my_delta_table ZORDER BY (name); -
清理(VACUUM):定期运行 `VACUUM` 命令清理不再需要的数据文件,释放存储空间。通常需要指定一个保留期(例如,7天),以确保时间旅行和并发读取的正确性。
VACUUM my_delta_table RETAIN 7 DAYS; - 模式演进:如果需要添加新列,并且数据源包含这些列,通常写入时如果启用了模式演进(autoMerge=true),Delta Lake 会自动处理。也可以使用 `ALTER TABLE ADD COLUMNS` 等 DDL 语句。
使用三角洲仓库的成本考量
使用三角洲仓库的成本主要来自于两个方面:数据存储和计算资源。
存储成本
三角洲仓库的数据和元数据(事务日志)存储在云对象存储上。云对象存储通常非常廉价,按实际存储的数据量计费。三角洲仓库的存储成本主要取决于:
- 数据量:存储的数据越多,成本越高。
- 保留策略:时间旅行功能会保留旧版本的数据文件。保留期越长,存储的数据量越大(直到运行 `VACUUM`)。合理设置 `VACUUM` 的保留策略很重要。
- 文件数量/大小:大量小文件会增加一些元数据开销,虽然不是主要成本,但会影响计算性能。定期运行 `OPTIMIZE` 合并文件有助于管理。
计算成本
与传统数据仓库不同,三角洲仓库的计算是分离的。你需要使用计算引擎(如 Spark 集群、Databricks SQL Endpoint、Trino 集群等)来执行读写操作。计算成本是主要的开销来源,取决于:
- 选择的计算引擎:不同的云平台和技术栈有不同的计费模式(按小时、按使用量、按查询等)。
-
工作负载类型和规模:
- 数据摄入 (Ingestion):处理和写入数据的计算量。增量写入和合并操作通常比全量覆盖更节省计算。
- 转换 (Transformation):清洗、聚合、关联等 ETL/ELT 任务所需的计算资源。
- 查询 (Querying):BI 报表、即席查询、数据科学探索等读取数据的工作负载。优化良好的 Delta 表(通过 `OPTIMIZE`、Z-ordering)可以显著减少查询所需扫描的数据量,从而降低计算成本。
- 维护操作:运行 `OPTIMIZE` 和 `VACUUM` 也需要计算资源。
- 计算集群/服务配置:使用的虚拟机类型、核心数量、内存大小、集群的运行时长等都会影响成本。采用自动伸缩的集群或无服务器计算服务有助于根据实际需求优化计算成本。
总体而言,通过合理的数据建模、高效的写入策略、定期的维护操作(`OPTIMIZE`, `VACUUM`)以及根据工作负载选择合适的计算资源,可以有效地管理和控制使用三角洲仓库的成本,使其成为一个高性能、高可靠且经济高效的大数据存储和分析解决方案。