Apache Spark 4.0 新特性解读与升级指南

聚焦 ANSI SQL 默认开启对存量作业的影响,给出分阶段迁移路径与关键 API 变更速查

袋鼠云
袋鼠云
国产信创

Apache Spark 4.0 默认开启 ANSI SQL 模式、移除 DataSet API、要求 Java 17 或更高版本,这三个 breaking change 对存量作业的影响面最大。本文聚焦 ANSI SQL 默认开启带来的实际影响,给出分阶段迁移路径和回滚策略,并附关键 API 变更速查表。

ANSI SQL 默认开启:对存量作业的真实冲击

Spark 4.0 将 spark.sql.mode 的默认值从 PERMISSIVE 改为 ANSI。这个改动看似只是一个配置项的变化,但实际影响范围远超预期。

字符串类型转换行为变化:在 PERMISSIVE 模式下,将字符串 "abc" 转为整型会返回 null;在 ANSI 模式下,这个操作会直接抛出 NumberFormatException。如果你的 ETL 作业中有类似 CAST(user_input AS INT) 的逻辑,且输入数据中存在脏数据,升级后作业会大面积失败。

类型提升限制:ANSI 模式禁止隐式窄化类型转换。例如将 INT 列直接赋值给 SHORT 列不再被允许,必须显式使用 CAST。这在 MERGE INTO 或 INSERT INTO 语句中尤为常见,因为很多存量代码依赖隐式转换来匹配目标表的 Schema。

浮点数比较:ANSI 模式下,NaN 不再等于 NaN(之前的行为是 NaN = NaN 返回 true),NULL 参与比较时的行为也更严格(NULL = NULL 返回 NULL 而不是 true)。这会影响条件过滤和去重逻辑。

实际评估方法:在升级前,先在 Spark 3.x 环境中设置 spark.sql.mode=ANSI 运行所有存量作业,收集所有报错。根据我的经验,一个中等规模的 ETL 集群(约 200 个作业)通常会暴露 30-50 个需要修改的地方,其中约 70% 是字符串到数值的隐式转换,20% 是隐式类型窄化,10% 是浮点数比较问题。

分阶段迁移路径

第一阶段:评估与准备(1-2 周)

在现有 Spark 3.x 集群上,对每个作业临时开启 ANSI 模式试运行。建议使用 spark.sql.mode=ANSI 作为默认配置,在测试环境中跑通所有作业的回放测试。记录所有失败的作业和失败原因,按影响程度分级:P0(核心 ETL 链路)、P1(分析查询)、P2(临时任务和 ad-hoc 查询)。

同时检查所有依赖的第三方库是否兼容 Spark 4.0。一些旧版本的 Spark 插件(如早期的 Delta Lake 版本、某些自定义 UDF 库)可能不兼容 4.0 的 API 变更。

第二阶段:P0 作业修复(2-3 周)

优先修复 P0 作业。常见的修复模式有三种:

一是将显式 CAST 替换为带 TRY_CAST 的安全转换。TRY_CAST 是 Spark 3.3 引入的函数,在转换失败时返回 null 而不是抛异常,行为与旧版 PERMISSIVE 模式一致。

二是对目标表 Schema 做兼容性修改。如果源表的 INT 列需要写入目标表的 SHORT 列,可以在 INSERT 前增加显式 CAST,或者修改目标表 Schema 使类型匹配。

三是在作业入口处显式设置 spark.sql.mode=PERMISSIVE,作为临时过渡方案。但这只是权宜之计,不应作为长期方案。

第三阶段:全量切换与验证(1 周)

将 P0 和 P1 作业全部切换到 Spark 4.0,观察 3-5 个工作日的运行情况。重点关注:作业失败率是否回到升级前的水平、数据质量指标(空值率、重复率)是否出现异常波动、作业运行时间是否在合理范围内。

大数据基础平台 EasyMR

统一存储、计算与运维,支撑批、流、OLAP 与湖仓一体的国产化大数据底座平台

了解产品

回滚策略

升级前必须制定回滚方案。核心要点:保留 Spark 3.x 的安装包和配置文件,在集群的部署工具中保留一键回滚脚本。如果 Spark 4.0 上线后出现大规模故障(如 30% 以上的作业失败),立即触发回滚。

回滚时需要注意数据兼容性。如果使用了 Spark 4.0 写入的新表(如使用了 Spark 4.0 的新数据类型或新函数),回滚到 3.x 后可能无法读取。建议在升级期间不要新建依赖 4.0 新特性的表。

DataSet API 移除的实际影响

Spark 4.0 正式移除了 DataSet API,只保留 DataFrame(即 Dataset[Row])。如果你的代码中有类似 ds.map(x => x.getInt(0)) 的操作,需要改为 DataFrame API 或使用 UDF。

受影响的场景主要有三类:一是使用了 map、flatMap、filter 等 Dataset 算子的 Scala/Java 代码,需要转换为 withColumn、select、filter 等 DataFrame 操作;二是使用了 Encoder 做类型序列化的代码,需要改用 Row 级别的操作;三是使用了 KeyValueGroupedDataset 进行分组聚合的代码,需要改用 groupBy + agg。

影响评估的方法:在代码库中搜索 Dataset[、\.map(、\.flatMap(、Encoder[ 等关键字。通常 Scala 代码库受影响较大,Python 代码库因为本身就只用 DataFrame API,影响几乎为零。

国产信创

面向国产化替代与信创改造场景,支撑数据平台平滑迁移、统一纳管、性能保障与安全可控。

了解解决方案

关键 API 变更速查

环境要求:Java 17 是最低版本,推荐使用 Java 21。Java 11 和更早版本不再支持。

配置变更:spark.sql.mode 默认值从 PERMISSIVE 变为 ANSI;spark.sql.legacy.timeParserPolicy 默认值从 PERMISSIVE 变为 EXCEPTION;spark.sql.ansi.enabled 已被移除(ANSI 模式现在通过 spark.sql.mode 统一控制)。

SQL 函数变更:移除了 compatibility 包下的旧版函数;unix_timestamp 和 to_timestamp 的默认时间格式从 yyyy-MM-dd HH:mm:ss 变为 yyyy-MM-dd'T'HH:mm:ss(遵循 ISO 8601);array、map 等函数的参数类型检查更严格。

DataFrame API 变更:移除了 Dataset.as[T] 类型转换方法;Column.expr 方法的行为更严格,不允许隐式解析未限定的列名;DataFrameStatFunctions 中的 corr、cov 方法的返回值类型从 Double 变为 Option[Double]。

Python API 变更:pyspark.sql.functions 中的部分函数签名变更,udf 注册方式有微调;SparkSession.builder 的部分配置方法被标记为 deprecated。

迁移检查清单

升级前逐项检查:确认 Java 版本为 17+;确认所有作业的 ANSI 模式兼容性;确认 DataSet API 使用情况并制定替换计划;确认第三方依赖(Delta Lake、Hudi、Iceberg 等)的版本兼容性;确认 PySpark 代码中没有使用已移除的函数;确认 JDBC 连接器的 URL 格式符合新版要求;保留 Spark 3.x 回滚包和配置备份;在测试环境完成全量作业回放。

开启Data+AI 之旅

填写表单,获取专属解决方案

400-002-1024

工作日 9:00-18:00

关注公众号

获取最新产品动态与技术干货

关注公众号

企业微信

扫码添加企业微信