3、环境搭建:安装 Spark、配置 Delta Lake、创建第一个 Delta 表

核心原理:Delta Lake 与 Spark 的运行时关系

Delta Lake 并非独立运行的存储引擎,而是构建在 Apache Spark 之上的事务性存储层。它通过一组 Spark 插件(Delta Spark 包)拦截并扩展 DataFrame 与 SQL 操作,将 ACID 事务、版本管理、时间旅行等能力注入标准 Spark 作业。理解这一架构对后续排障至关重要:Delta Lake 没有独立守护进程,所有读写都经由 Spark Executor 完成,而事务日志(_delta_log)则直接写入你指定的云存储或本地文件系统。

安装时需严格匹配三个核心组件的版本:Spark 版本、Delta Lake 插件版本、Scala 版本(Spark 2.4 使用 Scala 2.11/2.12,Spark 3.x 使用 Scala 2.12/2.13)。版本错配是初学者最常见的失败原因,例如 Spark 3.5 搭配 Delta Lake 1.0 会直接抛出 NoSuchMethodError。

版本兼容速查表(截至本课程编写时)

Spark 版本推荐的 Delta Lake 版本Scala 版本Python 兼容性
3.5.x3.2.x / 3.3.x2.123.8 – 3.11
3.4.x3.1.x / 3.2.x2.123.8 – 3.11
3.3.x2.4.x / 3.0.x2.123.7 – 3.10
2.4.x1.0.x(仅维护)2.11 / 2.122.7 / 3.5 – 3.7
用户代码 PySpark / Scala / SQL Apache Spark 引擎 Catalyst 优化器 + Tungsten 执行 Delta Lake 插件 事务日志 / 版本管理 / 约束 (通过 Spark 扩展 API 注入) 存储系统 HDFS / S3 / 本地文件 Parquet 数据文件 _delta_log 目录结构 00000000000000000000.json 00000000000000000001.json _last_checkpoint (每个 JSON 记录一次事务) 写入 版本演进示意(每次写操作产生新版本) v0 建表 v1 INSERT v2 UPDATE v3 DELETE

方法流程:从零搭建本地开发环境

以下流程以 macOS / Linux 本地模式为例,Windows 用户建议使用 WSL2 保持一致体验。整个过程约需 15 分钟,核心步骤为:安装 Java → 获取 Spark → 启动 PySpark 并加载 Delta 包 → 验证版本。

步骤 1:安装 Java 11 或 17

Delta Lake 3.x 要求 Java 8/11/17,推荐使用 Java 11 以获得最佳兼容性。检查现有环境:

java -version
# 期望输出包含 openjdk version "11.0.x" 或 "17.0.x"
# 若未安装,macOS 执行:brew install openjdk@11
# Ubuntu/Debian 执行:sudo apt install openjdk-11-jdk

步骤 2:下载并配置 Spark(无需 root 权限)

从 Apache 官网下载预编译版本,注意选择包含 Hadoop 的发行包:

cd ~/opt
wget https://dlcdn.apache.org/spark/spark-3.5.1/spark-3.5.1-bin-hadoop3.tgz
tar -xzf spark-3.5.1-bin-hadoop3.tgz
mv spark-3.5.1-bin-hadoop3 spark

# 配置环境变量(写入 ~/.bashrc 或 ~/.zshrc)
export SPARK_HOME="$HOME/opt/spark"
export PATH="$SPARK_HOME/bin:$PATH"
export PYSPARK_PYTHON=python3

步骤 3:启动 PySpark 并加载 Delta Lake 包

Delta Lake 以 Maven 坐标形式动态加载,无需手动下载 JAR 文件。使用 --packages 参数指定版本:

pyspark --packages io.delta:delta-spark_2.12:3.2.0 \
        --conf "spark.sql.extensions=io.delta.sql.DeltaSparkSessionExtension" \
        --conf "spark.sql.catalog.spark_catalog=org.apache.spark.sql.delta.catalog.DeltaCatalog"

启动成功后,在 PySpark 交互环境中执行以下验证:

spark.version
# 输出:'3.5.1'

delta_version = spark.conf.get("spark.sql.extensions")
print(delta_version)
# 输出:io.delta.sql.DeltaSparkSessionExtension

生产环境提示:若使用 Spark Submit 提交作业,将上述 --packages 和 --conf 参数原样添加到提交命令即可。企业内网无法访问 Maven 中央仓库时,需提前下载 JAR 包并放置于 $SPARK_HOME/jars 目录,或使用 --repositories 指向内部镜像。

案例实战:创建第一个 Delta 表并验证事务特性

环境就绪后,我们通过一个完整案例创建 Delta 表,并验证其核心的 ACID 特性。以下代码在 PySpark 中逐行执行:

# 1. 创建 Delta 表(路径方式,不依赖 Hive Metastore)
df = spark.range(5).toDF("id")
df.write.format("delta").save("/tmp/delta_student")

# 2. 读取并显示数据
spark.read.format("delta").load("/tmp/delta_student").show()
# +---+
# | id|
# +---+
# |  0|
# |  1|
# |  2|
# |  3|
# |  4|
# +---+

# 3. 执行一次 UPDATE 操作(产生新版本)
from delta.tables import DeltaTable
delta_table = DeltaTable.forPath(spark, "/tmp/delta_student")
delta_table.update(
    condition="id < 3",
    set={"id": "id + 100"}
)

# 4. 验证数据已更新
spark.read.format("delta").load("/tmp/delta_student").show()
# +---+
# | id|
# +---+
# |100|
# |101|
# |102|
# |  3|
# |  4|
# +---+

# 5. 时间旅行:查询原始版本(版本 0)
spark.read.format("delta") \
     .option("versionAsOf", 0) \
     .load("/tmp/delta_student") \
     .show()
# 输出原始 0-4 数据,证明历史版本可回溯

执行完毕后,查看表目录结构,你会看到 _delta_log 文件夹中已生成多个 JSON 事务日志文件:

ls -la /tmp/delta_student/
# 输出示例:
# _delta_log/
# part-00000-xxx-c000.snappy.parquet
# part-00001-xxx-c000.snappy.parquet

ls /tmp/delta_student/_delta_log/
# 00000000000000000000.json
# 00000000000000000001.json

误区与复盘:环境搭建中的常见陷阱

陷阱 1:版本号随意搭配。很多初学者直接使用 --packages io.delta:delta-core_2.12:2.0.0 搭配 Spark 3.5,导致运行时抛出 java.lang.NoSuchMethodError。务必参考官方兼容矩阵,本课程推荐 Spark 3.5.1 + Delta 3.2.0。

陷阱 2:忘记配置 Spark 扩展。仅添加 --packages 而不设置 spark.sql.extensions 和 spark.sql.catalog.spark_catalog,会导致 format("delta") 操作报错 Unsupported data source type。这两个配置是 Delta Lake 与 Spark 深度集成的关键。

陷阱 3:混淆表名与路径。使用 save("/tmp/delta_student") 创建的是路径表,不注册到 Hive Metastore。若使用 saveAsTable("student") 则创建元数据表,默认存储位置在 Spark 的 warehouse 目录下。两者的事务日志机制相同,但管理方式不同。

复盘清单:环境搭建是否成功,可通过以下 4 项快速自检:

  • spark.version 输出与预期一致,无 Python/Scala 版本冲突。
  • spark.conf.get("spark.sql.extensions") 返回 Delta 扩展类全名。
  • 执行 spark.range(1).write.format("delta").save("/tmp/test_delta") 无异常。
  • 查看目标目录,确认 _delta_log 文件夹已生成且包含至少一个 JSON 文件。