Spark on YARN 作业提交时常用的参数

一、动态资源分配(让集群按需增减 Executor)

  • spark.dynamicAllocation.enabled=true

    开启动态资源分配。Spark 会根据任务负载自动请求新 Executor 或释放空闲 Executor,避免资源浪费。

  • spark.shuffle.service.enabled=true

    开启外部 Shuffle 服务。这是动态资源分配的前提,保证 Executor 被回收时,其上产生的 Shuffle 数据仍能被其他节点读取。

  • spark.dynamicAllocation.maxExecutors=150

    动态分配时,最多申请 150 个 Executor(即使负载再高也不超过此数)。结合下面显式设置的 --num-executors 120,意味着初始启动 120 个,繁忙时可弹性扩至 150。

  • spark.dynamicAllocation.cachedExecutorIdleTimeout=60

    持有缓存数据的 Executor 空闲超过 60 秒后,也会被回收。默认是无限大(永不回收),设为 60 可更快释放资源。


二、Shuffle 并行度与网络传输(直接影响数据分布和性能)

  • spark.sql.shuffle.partitions=14000

    设置 Shuffle 操作(如 JOINGROUP BY)产生的默认分区数为 14000。这个值直接决定了 Reducer 的数量。

  • spark.shuffle.file.buffer=64K

    Shuffle 写文件时,每个分区使用的内存缓冲区大小为 64 KB。适当增大可减少磁盘 I/O 次数(默认 32K)。

  • spark.reducer.maxSizeInFlight=96M

    Reducer 从 Mapper 端拉取数据时,单次请求的最大数据量为 96 MB(默认 48M)。加大可提升吞吐,但会消耗更多内存。

  • spark.shuffle.io.retryWait=20

    Shuffle 网络请求失败时的重试等待间隔(秒)。默认可能更短,设为 20 秒表示在网络抖动时给更长的恢复时间。

  • spark.shuffle.memoryFraction=0.8

    (旧版参数) 指定 JVM 堆内存中用于 Shuffle 聚合和排序的比例为 80%。在 Spark 1.6 之前用于控制 Shuffle 内存池大小,新版已废弃,使用 spark.memory.fraction 统一管理。如果版本较老,此参数仍会生效。

  • spark.shuffle.consolidateFiles=true

    (旧版参数) 开启 Shuffle 文件合并。将同一批次任务产生的多个中间 Shuffle 小文件合并成更少的文件,以减少磁盘随机读写压力。在 Spark 1.6 以后,此机制已被更优的排序式 Shuffle 取代,若仍在使用,可能是为了兼容历史版本。


三、内存与 GC(Executor 进程级资源控制)

  • spark.executor.memoryOverhead=6G

    Executor 的堆外内存为 6 GB。这部分内存用于 JVM 自身开销、网络缓冲、字符串常量池等。结合 --executor-memory 40G,每个 Executor 容器向 YARN 申请的物理总内存为 40 + 6 = 46 GB

  • spark.executor.extraJavaOptions=-XX:+UseG1GC -XX:ParallelGCThreads=10

    给 Executor JVM 传递额外参数,这里指定使用 G1 垃圾回收器(适合大堆、低延迟场景),并设置并行 GC 线程数为 10(通常与核心数 --executor-cores 10 匹配)。


四、IO 压缩与 Parquet 兼容性

  • spark.io.compression.codec=org.apache.spark.io.ZStdCompressionCodec

    使用 ZStandard(Zstd)作为 Shuffle 数据和中间结果的压缩算法。相比默认的 LZ4,Zstd 压缩率更高,能显著减少 Shuffle 传输量,代价是轻微增加 CPU。

  • spark.sql.parquet.enableVectorizedReader=false

    关闭 Parquet 向量化读。可能因为数据中有复杂嵌套字段或部分列类型不兼容向量化,强制走逐行读,保证正确性。

  • spark.sql.storeAssignmentPolicy=LEGACY

    表数据写入时的类型转换策略设为 LEGACY,即遵循 Spark 2.x 的宽松规则(允许一些默认禁止的类型强转),用于兼容老数据。

  • spark.sql.parquet.int96RebaseModeInRead=LEGACY

    读取 Parquet 文件时,对于 INT96 格式的时间戳,使用旧版时区偏移方式。这通常是为了与 Hive 老版本写入的 Parquet 时间戳字段保持一致,避免读取时出现时区偏移错误。

  • spark.sql.sources.partitionOverwriteMode=dynamic

    动态分区覆写模式。当执行 INSERT OVERWRITE TABLE 时,只覆盖语句中实际涉及的那些分区,不会清空整表。这能防止误删其他日期的数据。


五、PySpark 环境与依赖

  • spark.yarn.appMasterEnv.PYSPARK_PYTHON=/usr/bin/python3.8

    设置 YARN ApplicationMaster 容器内 Python 解释器路径。

  • spark.pyspark.driver.python=/usr/bin/python3.8

    Driver 端使用的 Python 路径。

  • spark.pyspark.python=python3env/usr/bin/python3.8

    Executor 端使用的 Python 路径(可能指向一个自定义虚拟环境 python3env)。

  • --py-files hdfs:///user/hive/jinja2.zip,hdfs:///user/hive/markupsafe.zip

    分发到所有节点的 Python 依赖包(这里是 Jinja2 模板引擎及其依赖 MarkupSafe),供 PySpark 脚本使用。


六、基础资源规格(静态分配部分)

  • --executor-cores 10

    每个 Executor 使用 10 个 CPU 核心。

  • --executor-memory 40G

    每个 Executor 堆内内存 40 GB。

  • --driver-cores 8

    Driver 使用 8 个核心。

  • --driver-memory 20G

    Driver 内存 20 GB。

  • --num-executors 120

    启动时请求 120 个 Executor。因为开了动态分配,这是初始数量,后续可根据负载在 120~150 之间浮动。

  • --master yarn

    使用 YARN 作为集群管理器。

  • --deploy-mode cluster

    Driver 运行在 YARN 集群的某个节点上,而非提交任务的客户端。

  • --queue warehouse

    任务提交到 YARN 队列 warehouse

  • --name jms_dwd__...

    为这个 Spark 应用设置显示名称,便于在 YARN UI 中识别。