Loading......

文章背景图

✨Spark 内存模型

2025-11-26
7
-
- 分钟

Spark 作为典型的 内存计算框架,其性能高度依赖内存管理机制。
Executor 是实际执行 Task 的核心单元,因此 Spark 的内存模型主要围绕 Executor 端 JVM 内存 展开。

Spark 内存经历过两代模型:

  • 静态内存管理(Spark 1.6 之前)

  • 统一内存管理 / 动态内存管理(Spark 1.6 之后,默认)


Spark 内存模型基础

🧠 为什么 Spark 强依赖内存?

Spark 中:

  1. Task 执行计算(如 shuffle、聚合、join)需要执行内存

  2. RDD/DataFrame 缓存 需要存储内存

  3. 内存不足可能导致

    • 频繁 GC

    • Shuffle spill(落盘)

    • Out Of Memory 错误

    • 性能大幅下降

因此 Spark 必须设计一套 高效的内存分配机制


Executor 进程内存分布概览

Executor 是 JVM 进程,其内存大体分为:

🗄️ 堆内内存(In-Heap Memory)

  • 存储 JVM 对象

  • 由 JVM GC 管理

  • 主要用于:RDD 数据、执行内存数据结构、Shuffle 内部对象

📦 堆外内存(Off-Heap Memory)

  • 不受 JVM GC 管理

  • Spark 通过 Unsafe API / Netty 手动管理

  • 主要用于:

    • Tungsten 内部的二进制存储

    • Shuffle 数据

    • 内存列式缓存

堆外内存能减少 GC 频率,提高大数据任务性能。


✨ 静态内存管理(Spark 1.6 之前)

这是 Spark 最早的内存管理模型,特点是 固定比例、无法动态调节,在任务特性较复杂的场景下会造成大量资源浪费。


🔧 静态内存整体结构

Executor 堆内内存被划为 3 大部分(固定比例):

区域

比例

作用

Storage 内存

60%

RDD Cache、Broadcast、Unroll

Execution 内存

20%

Shuffle、join、聚合、排序

Other 内存

20%

用户自定义对象、元数据

🎯 补充:Unroll Memory

RDD 缓存过程中,为将数据从计算状态转换为缓存状态,需要临时占用内存,此过程为 unroll,由 Storage 管理。


📌 静态内存管理的主要参数

  • spark.storage.memoryFraction(默认 0.6)
    控制 Storage 内存占比

  • spark.shuffle.memoryFraction(默认 0.2)
    控制 Execution(Shuffle)内存占比

堆外内存固定约 380MB,不可变。


👍 静态模型优点

  • 内存规划简单、结构明确

  • 在任务结构稳定时表现可预测


👎 静态模型缺点(被淘汰的根本原因)

① 固定比例导致资源浪费

Storage 空闲、Execution 紧张 → 无法互相借内存
→ 造成频繁 spill,性能急剧下降

② 无法适配不同任务的内存需求

任务类型多样:

  • 有的计算密集

  • 有的缓存密集
    固定比例会导致资源失衡

③ 调优困难

只能靠修改 JVM 内存参数、调比例 → 成本极高

因此 Spark 在 1.6 之后正式采用 统一内存管理模型


✨ 统一内存管理(Spark 1.6+ 默认)

为解决静态模型的缺陷,Spark 引入了 动态共享机制,让 Storage 和 Execution 可以互相借用内存,大幅提升灵活性与性能。


🔧 统一内存整体架构

Executor 内存被分成两大部分:

区域

描述

保留内存(Reserved Memory)

Spark 内部保留,不对用户任务开放

可用内存(Usable Memory)

由 Storage + Execution 动态共享

可用内存中:

  • Storage 默认可用:50%

  • Execution 默认可用:50%


🔄 动态共享机制(核心机制)

🟢 Storage 空闲 → Execution 可以“抢占”

大量 shuffle 时,Execution 能借用 Storage 的空闲空间。

🟣 Execution 空闲 → Storage 可以扩容

需要缓存大量数据时,可用内存不足 → Storage 自动扩容。

不过有一条 不对称规则

抢占类型

是否必须归还?

Execution 抢 Storage

❌ 不需要立即归还

Storage 抢 Execution

✅ 必须在压力下归还

这是为了保证任务执行不会因内存不足而失败。


📦 堆外内存在统一内存中的角色

堆外内存和静态时代一致:

  • 主要服务于 Tungsten、Shuffle、序列化等

  • 减少 GC 参与,提高性能

  • 更适合大规模数据处理


✨ 静态内存管理 vs 统一内存管理(对比总结)

对比项

静态内存管理

统一内存管理

分配方式

固定比例

动态共享

Storage 与 Execution

隔离

同池共享

适应性

性能

容易 spill

更高效稳定

调优难度

默认模式

旧版本

Spark 1.6+

统一内存管理对性能提升极其明显,是 Spark 默认推荐的方案。


✨ 工作中常用 Spark 内存调优建议

🎯 资源配置建议

  • Executor 资源:
    CPU : Memory = 1 : 3 或 1 : 4(常用经验值)

  • 内存不能盲目扩大:会导致 GC 压力 ↑

  • 内存过小:spill ↑,性能下降明显


🎯 重要调优参数

  • --num-executors:执行并行度

  • --executor-memory:单节点内存

  • --executor-cores:每个 Executor 并发度

  • --driver-memory:Driver 内存

  • spark.sql.adaptive.enabled=true:开启自适应执行(推荐)

评论交流