Delta Lake 在 Spark 3.2.2 + YARN 环境下的集成与问题解决全记录
1. 背景与需求
在现有 Hive 3.x + Spark 3.x + YARN 的集群中,我们希望引入 Delta Lake 作为数据湖的事务存储层,以解决 Hive ACID 表与 Spark 之间的兼容性问题(尤其是 Spark 无法直接读取 Hive ACID 托管表)。要求:不影响现有 Hive 服务,无需重启 HDFS 或 YARN。
2. Delta Lake 简介与优势
Delta Lake 是一个开源的数据湖存储格式,为 Parquet 文件带来了 ACID 事务、时间旅行、Schema 演化等特性。它与 Spark 深度集成,性能优异。
与 Hive ACID 的核心对比
| 特性 | Hive ACID | Delta Lake |
|---|---|---|
| 存储格式 | 仅 ORC | Parquet |
| 元数据管理 | Hive Metastore (RDBMS) | _delta_log 事务日志目录 |
| 与 Spark 集成 | 需 Hive Warehouse Connector (HWC),兼容性差 | 原生支持,无需额外组件 |
| 并发控制 | 锁机制 + 乐观并发 | 乐观并发 (文件级冲突检测) |
| Schema 演化 | 有限(主要添加列) | 完整(添加/删除/重命名/修改列) |
| 时间旅行 | 复杂 | 原生支持 VERSION AS OF |
| 写入模式 | 增量文件 (Delta Files) | 写时复制 + 日志记录 |
结论:以 Spark 为核心的技术栈,Delta Lake 是更优选择。
3. 安装 Delta Lake ------ 无需重启 HDFS/YARN
Delta Lake 仅仅是一个 Spark 插件库,通过 JAR 包集成,不需要重启任何集群服务。
3.1 版本选择
你的 Spark 版本为 3.2.2 ,根据官方兼容性列表,推荐使用 Delta Lake 2.x 系列。具体版本对应:
| Spark 版本 | Delta Lake 推荐版本 | 包名示例 |
|---|---|---|
| 3.2.x | 2.0.x (如 2.0.2) | delta-core_2.12-2.0.2.jar |
| 3.3.x | 2.4.x | delta-spark_2.12-2.4.0.jar |
| 3.4.x | 2.4.x 或更高 | ... |
重要 :Delta Lake 2.x 的 Maven artifactId 为
delta-core_2.12,3.x 后改为delta-spark_2.12。因此下载 2.0.2 时应使用delta-core_2.12-2.0.2.jar。
3.2 下载 JAR 包(内网环境使用国内镜像)
由于内网机器无法访问外网,我们使用国内 Maven 镜像站下载。需要同时下载 核心包 和 存储模块包 (Delta Lake 2.x 将存储层独立为 delta-storage)。
阿里云镜像(推荐):
- 核心包:
https://maven.aliyun.com/repository/public/io/delta/delta-core_2.12/2.0.2/delta-core_2.12-2.0.2.jar - 存储包:
https://maven.aliyun.com/repository/public/io/delta/delta-storage_2.12/2.0.2/delta-storage_2.12-2.0.2.jar
清华大学镜像:
- 核心包:
https://mirrors.tuna.tsinghua.edu.cn/maven2/io/delta/delta-core_2.12/2.0.2/delta-core_2.12-2.0.2.jar - 存储包:
https://mirrors.tuna.tsinghua.edu.cn/maven2/io/delta/delta-storage_2.12/2.0.2/delta-storage_2.12-2.0.2.jar
华为云镜像:
- 核心包:
https://mirrors.huaweicloud.com/repository/maven/io/delta/delta-core_2.12/2.0.2/delta-core_2.12-2.0.2.jar - 存储包:
https://mirrors.huaweicloud.com/repository/maven/io/delta/delta-storage_2.12/2.0.2/delta-storage_2.12-2.0.2.jar
在有外网的机器上下载后,将两个 JAR 包传输到内网环境。
3.3 部署到集群
方法一 :将 JAR 包复制到所有节点的 $SPARK_HOME/jars/ 目录。
方法二 :在提交任务时通过 --jars 参数指定(推荐测试阶段使用)。
分发脚本示例:
bash
#!/bin/bash
DELTA_CORE_JAR="delta-core_2.12-2.0.2.jar"
DELTA_STORAGE_JAR="delta-storage_2.12-2.0.2.jar"
SPARK_HOME="/opt/spark"
NODES="node1 node2 node3"
for node in $NODES; do
scp $DELTA_CORE_JAR $node:$SPARK_HOME/jars/
scp $DELTA_STORAGE_JAR $node:$SPARK_HOME/jars/
done
3.4 配置 Spark
编辑 $SPARK_HOME/conf/spark-defaults.conf,追加以下内容(并分发到所有节点):
bash
spark.sql.extensions=io.delta.sql.DeltaSparkSessionExtension
spark.sql.catalog.spark_catalog=org.apache.spark.sql.delta.catalog.DeltaCatalog
验证安装
4.1 简单测试
启动 pyspark 并执行:
python
from pyspark.sql import SparkSession
spark = SparkSession.builder.appName("DeltaTest").getOrCreate()
data = spark.range(0, 5)
data.write.format("delta").save("/tmp/delta-test")
df = spark.read.format("delta").load("/tmp/delta-test")
df.show()
预期输出:
bash
+---+
| id|
+---+
| 0|
| 1|
| 2|
| 3|
| 4|
+---+
4.2 常见错误及解决
- 错误1:java.lang.NoSuchMethodError: ...
SQLConf$.PARQUET_FIELD_ID_READ_ENABLED
原因:使用了为更高版本 Spark(如 3.3+)编译的 Delta Lake JAR(例如 delta-spark_2.12-3.x.x.jar),其中调用了 Spark 3.2 不存在的 API。
解决:降级到 Delta Lake 2.x 系列,使用 delta-core_2.12-2.0.2.jar,而非 delta-spark_2.12。
- 错误2:NoClassDefFoundError: io/delta/storage/LogStore
原因:Delta Lake 2.x 将存储层独立为 delta-storage 模块,仅添加 delta-core 会导致该错误。
解决:必须同时包含 delta-storage JAR 包。请确保在 --jars 或 $SPARK_HOME/jars/ 中同时存在两个 JAR。
将 Hive 现有 Parquet 表转换为 Delta 表
Delta Lake 提供了原地升级命令,无需重写数据:
sql
CONVERT TO DELTA [database_name.]table_name;
如果希望 Delta 表自动注册到 Hive Metastore,请在创建 SparkSession 时启用 Hive 支持:(其实上面配置文件已经添加了,这里就不需要追加了)
bash
spark = SparkSession.builder \
.enableHiveSupport() \
.config("spark.sql.extensions", "io.delta.sql.DeltaSparkSessionExtension") \
.config("spark.sql.catalog.spark_catalog", "org.apache.spark.sql.delta.catalog.DeltaCatalog") \
.getOrCreate()
delta lake日常维护命令
Delta Lake 日常维护命令
| 操作 | 命令 | 说明 |
|---|---|---|
| 合并小文件 | OPTIMIZE table_name |
提升查询性能,可指定分区 OPTIMIZE table_name WHERE dt='202606' |
| 清理旧版本 | VACUUM table_name RETAIN 168 HOURS |
物理删除 7 天前的文件(默认保留 7 天),也可用 VACUUM table_name 使用默认值 |
| 查看历史 | DESCRIBE HISTORY table_name |
显示所有版本及操作,包括版本号、操作时间、操作类型等 |
| 时间旅行(按版本) | SELECT * FROM table_name VERSION AS OF 5 |
查询第 5 个快照的数据 |
| 时间旅行(按时间戳) | SELECT * FROM table_name TIMESTAMP AS OF '2024-01-01' |
查询指定时间点的快照数据 |
| 查看表详细信息 | DESCRIBE DETAIL table_name |
显示表的大小、文件数、分区数、格式等元数据 |
| 设置表属性 | ALTER TABLE table_name SET TBLPROPERTIES ('key'='value') |
例如调整日志保留期 delta.logRetentionDuration = interval 30 days |
| 转换现有 Parquet 表 | CONVERT TO DELTA [database.]table_name |
原地将 Parquet 表升级为 Delta 表,不重写数据 |
7. 总结
通过以上步骤,我们在不重启任何集群服务的前提下,成功为 Spark 3.2.2 + YARN 环境集成了 Delta Lake。核心要点:
Delta Lake 只是一个 Spark 插件,无需修改 HDFS/YARN。
Spark 3.2.x 必须使用 Delta Lake 2.x(delta-core_2.12 + delta-storage_2.12)。
国内镜像(阿里云、清华、华为云)可获取 JAR 包。
配置 spark.sql.extensions 和 spark.sql.catalog.spark_catalog 即可启用。
遇到 NoSuchMethodError 或 NoClassDefFoundError 基本都是版本不匹配或缺少 delta-storage 导致。
Delta Lake 完美解决了 Hive ACID 表与 Spark 不兼容的痛点,为数据湖提供了可靠的事务能力。如果需要更深入的功能(如 Schema 演化、Merge、流式读写入),可参考delta-lale官方文档
附:完整验证脚本
python
from pyspark.sql import SparkSession
spark = SparkSession.builder \
.appName("DeltaDemo") \
.config("spark.sql.extensions", "io.delta.sql.DeltaSparkSessionExtension") \
.config("spark.sql.catalog.spark_catalog", "org.apache.spark.sql.delta.catalog.DeltaCatalog") \
.getOrCreate()
# 创建并写入
df = spark.range(100)
df.write.format("delta").mode("overwrite").save("/tmp/delta_sample")
# 读取验证
spark.read.format("delta").load("/tmp/delta_sample").show(5)
# 更新操作
from delta.tables import DeltaTable
delta_table = DeltaTable.forPath(spark, "/tmp/delta_sample")
delta_table.update("id < 10", {"id": "id + 100"})
# 查看历史
spark.sql("DESCRIBE HISTORY delta.`/tmp/delta_sample`").show(truncate=False)
spark.stop()