spark统一内存模型 详解

        Apache Spark 是一个用于大规模数据处理的分布式计算框架,它支持多种处理模型(如批处理、流处理、SQL、机器学习等)。为了高效地在分布式环境中处理这些多样化的工作负载,Spark 在 2.x 版本后引入了统一内存管理模型,以便在不同类型的计算和存储任务之间合理分配和管理内存。

        本文将详细全面地从底层原理和部分源代码的角度解释 Spark 的统一内存模型,涵盖其内存管理的基本思想、不同的内存区域划分、动态内存管理机制以及具体的内存分配和回收机制。

1. Spark 的内存管理问题

        Spark 处理大量数据时,内存是一个关键的资源。传统的内存管理模型(Spark 1.x)中,内存资源主要被划分为两部分:

  1. 存储内存(Storage Memory):用于缓存中间计算结果(如 RDD Cache 或 Broadcast 变量)。
  2. 执行内存(Execution Memory):用于执行任务时的数据操作(如 shuffle、join、sort 时的数据缓冲区)。

        在 1.x 版本中,这两部分内存是彼此隔离的,存储内存和执行内存之间的使用是静态分配的。如果一部分内存不足,而另一部分有多余内存,无法进行灵活共享。这个问题在 2.x 版本中得到了改进,引入了统一内存管理模型

2. 统一内存管理模型的基本思想

        在 Spark 2.x 版本中(其实是1.6以后就出现了),内存模型的核心思想是通过动态调整存储内存和执行内存之间的划分,使得内存资源在运行时能够根据实际需要进行分配。这个动态分配机制使得在某些场景下(如缓存使用较少或执行任务不密集时),存储内存和执行内存可以灵活地共享内存资源。

统一内存模型主要有两个核心区域:

  1. 堆内内存(On-heap Memory):通过 JVM 堆来管理的内存,用于存储和操作数据。
  2. 堆外内存(Off-heap Memory):不在 JVM 堆中管理的内存,通常通过 sun.misc.Unsafe 或者直接的操作系统调用进行分配和管理,用于减少 JVM 垃圾回收(GC)的影响。

统一内存管理的核心在内存区域的动态占用机制,其占用规则如下:

  • 双方空间都不足时,则存储到硬盘;如己方空间不足而对方空余时,可借用对方的空间;(存储空间不足是指不足以放下一个完整的 Block)。
  • 执行内存的空间被对方占用后,可让对方将占用的部分存储转存到硬盘,然后“归还”借用的空间。
  • 存储内存的空间被对方占用后,无法让对方“归还”,因为需要考虑到 Shuffle 过程中很多因素,实现起来较为复杂。

Spark 的内存管理通过两个子模块进行控制:

  • 静态内存管理(Static Memory Management):用户根据应用程序需求预定义内存分配策略,Spark 不会动态调整分配。
     
  • 动态内存管理(Dynamic Memory Management):Spark 动态调整内存的使用以提高资源利用率。

3. Spark 内存的核心划分

在 Spark 中,内存被分为如下几个区域:

  1. Reserved Memory(保留内存):这部分内存用于 Spark 内部一些核心的操作,如内存管理、任务调度等。通常是一个固定的小比例,默认情况下保留 300MB。

  2. User Memory(用户内存):这部分内存用于存放用户数据结构、内存中的对象等。主要用来执行非 Spark 任务本身的数据操作(如用户自定义的代码)。

  3. Execution Memory(执行内存):用于执行任务时所需的内存,如进行 shuffle、join、sort 等操作时的数据缓冲区。

  4. Storage Memory(存储内存):用于缓存 RDD 的中间计算结果、广播变量等。它可以通过 persist 或 cache 方法将数据保存在内存中,以便重用。

4. 动态内存管理机制

        Spark 的统一内存管理模型采用动态内存管理机制,允许 Execution Memory 和 Storage Memory 在一定条件下共享内存资源。当 Execution Memory 或 Storage Memory 的使用量较低时,未被使用的部分可以被另一方临时使用。

4.1 动态分配策略

动态分配策略的核心机制体现在如下几点:

  1. 共享机制Execution Memory 和 Storage Memory 在需要时可以动态调整各自的内存占用,但两者总内存使用不会超过可用内存的最大限制(spark.memory.fraction,默认为 0.75,即 JVM 堆内存的 75%)。
  2. 逐步收回:当 Execution Memory 需要更多内存时,Spark 会首先尝试从 Storage Memory 中回收未使用的缓存空间。如果缓存的数据占满了存储内存且不能被回收,任务执行可能会出现内存不足。
  3. 溢出磁盘:当 Execution Memory 或 Storage Memory 超过了指定的内存限制时,Spark 会将部分数据溢出到磁盘以保证内存的有效使用。

5. Spark 统一内存模型的源代码解析

        接下来,我们深入解析 Spark 的内存管理相关的核心源代码,了解其底层实现。

5.1 UnifiedMemoryManager(统一内存管理器)

        UnifiedMemoryManager 是 Spark 内部管理内存的核心类。它负责跟踪和分配 Execution Memory 和 Storage Memory,并根据内存使用情况动态调整内存划分。

class UnifiedMemoryManager(override val maxHeapMemory: Long,memoryFraction: Double,storageRegionSize: Long,onHeapStorageMemory: Long,offHeapStorageMemory: Long) extends MemoryManager {// 计算执行内存的最大限制,基于 memoryFraction 参数private val maxExecutionMemory = (maxHeapMemory * memoryFraction).toLong// 当前已分配的执行内存private var executionMemoryUsed = 0L// 当前已分配的存储内存private var storageMemoryUsed = 0L// 获取执行内存的接口override def acquireExecutionMemory(numBytes: Long,taskAttemptId: Long,memoryMode: MemoryMode): Long = {val availableExecutionMemory = maxExecutionMemory - executionMemoryUsedval memoryToAcquire = math.min(numBytes, availableExecutionMemory)executionMemoryUsed += memoryToAcquirememoryToAcquire}// 获取存储内存的接口override def acquireStorageMemory(blockId: BlockId,numBytes: Long,memoryMode: MemoryMode): Boolean = {val availableStorageMemory = maxStorageMemory - storageMemoryUsedif (availableStorageMemory >= numBytes) {storageMemoryUsed += numBytestrue} else {false}}
}

在这个类中:

  • maxExecutionMemory:表示执行内存的最大限制,基于 memoryFraction 参数计算得出。
  • acquireExecutionMemory:负责从执行内存中分配指定数量的内存。如果当前执行内存不足,Spark 会根据内存使用情况尝试回收存储内存。
  • acquireStorageMemory:负责为存储缓存(如 RDD Cache)分配内存。如果当前的存储内存不足,Spark 会首先尝试从执行内存中获取未使用的部分。
5.2 动态调整机制

        Spark 的内存管理器能够动态地调整执行内存和存储内存之间的分配。通过以下两个方法来实现动态调整:

  • executionMemoryUsed:记录当前执行任务已经使用的执行内存。当执行任务完成后,内存会被释放并归还给内存池。
  • storageMemoryUsed:记录当前用于缓存数据的存储内存。当存储的 RDD 被移除或者被淘汰时,内存会被释放。

        当 Execution Memory 需要更多内存时,acquireExecutionMemory 会检查 Storage Memory 是否有未使用的部分,然后回收这些内存。

5.3 内存的申请与释放

内存的申请和释放是通过以下两个核心方法实现的:

  • 申请内存:在 acquireExecutionMemory 或 acquireStorageMemory 中,系统根据当前的内存使用情况分配内存,并调整 executionMemoryUsed 和 storageMemoryUsed
  • 释放内存:当任务执行完成或缓存不再需要时,通过 releaseExecutionMemory 或 releaseStorageMemory 将内存归还给系统。
def releaseExecutionMemory(numBytes: Long, taskAttemptId: Long, memoryMode: MemoryMode): Unit = {executionMemoryUsed -= numBytes
}def releaseStorageMemory(numBytes: Long, blockId: BlockId, memoryMode: MemoryMode): Unit = {storageMemoryUsed -= numBytes
}

5.4 内存的动态扩展

        当 Execution Memory 或 Storage Memory 无法满足需求时,Spark 会尝试动态扩展内存的使用。MemoryManager 会检查其他内存池是否有未使用的内存,如果有,则可以临时借用部分内存。

        例如,在 acquireExecutionMemory 中,Spark 会首先检查是否有足够的执行内存,如果不足,则会从存储内存中回收未使用的部分:

val memoryToBorrow = math.min(availableStorageMemory, numBytes - availableExecutionMemory)
executionMemoryUsed += memoryToBorrow

        这种机制保证了 Spark 在内存不足时,能够尽量通过动态扩展来提高内存的利用率,避免因内存不足而导致任务失败。

6. 堆外内存管理

        Spark 还支持堆外内存(Off-heap Memory)的管理,主要用于减少 JVM 垃圾回收的开销。在堆外内存模式下,Spark 会绕过 JVM 堆,通过操作系统直接分配和管理内存。

        堆外内存的管理通过 sun.misc.Unsafe 或者 Netty 框架来实现,具体机制与堆内内存管理类似,不过它的内存分配不受 JVM 堆限制,因此能够在某些场景下提供更高的性能。

        用户可以通过配置 spark.memory.offHeap.enabled 参数启用堆外内存管理,同时设置 spark.memory.offHeap.size 来指定堆外内存的大小。

7. 内存回收与垃圾回收

        Spark 的内存回收机制与 JVM 的垃圾回收机制密切相关。当内存管理器检测到内存不足时,Spark 会尝试触发垃圾回收(GC),以回收未使用的对象和内存。

        Spark 内存管理器与 GC 结合紧密,特别是当执行任务时,临时对象会频繁创建并在任务结束后被回收。因此,适当的 GC 策略(如 G1、CMS)对于 Spark 应用的性能至关重要。

        Spark 还提供了多种 GC 调优选项,用户可以通过调整 JVM 参数(如 -Xmx-XX:MaxGCPauseMillis)和 Spark 参数(如 spark.memory.fractionspark.memory.storageFraction)来优化内存使用和垃圾回收。

总结

        Spark 的统一内存模型通过动态调整执行内存和存储内存的划分,极大地提高了内存资源的利用率。通过引入堆外内存支持、灵活的内存共享机制以及动态扩展策略,Spark 能够在不同类型的任务(如批处理、流处理、机器学习)之间高效地分配和管理内存资源。

        我们从底层原理和源代码的角度详细解析了 Spark 内存管理的工作机制,了解了 UnifiedMemoryManager 如何动态管理和调度内存,以及内存的申请、释放与回收机制。掌握这些底层实现细节有助于在实际应用中优化 Spark 性能,提升资源利用率。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/454053.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mycat2安装配置

安装配置 安装 目前Mycat2下载地址已经不可访问,安装包可从参考资料[1]获取 下载后解压zip文件,将jar放在lib目录下 编辑配置文件 编辑conf文件夹下的prototypeDs.datasource.json 更改数据库相关信息 启动 windows环境下启动Mycat 以管理员身份运行…

Linux重点yum源配置

1.配置在线源 2.配置本地源 3.安装软件包 4.测试yum源配置 5.卸载软件包

Git 完整教程:版本管理、分支操作与远程仓库解析

文章目录 一、引言二、Git原理三、.git目录四、版本回退以及撤销修改五、Git远程控制1、创建仓库2、克隆/下载远程仓库到本地的方法3、本地仓库的修改推送到远程仓库4、拉取远程仓库的修改到本地仓库5、操作标签 六、Git分支1、分支操作(创建、删除、合并&#xff0…

九种排序,一次满足

我们在算法题进行练习提升时,经常会看到题目要求数据从大到小输出,从小到大输出,前一半从小到大输出,后一半从大到小输出等,那么这时候就需要用到排序算法,通过排序算法将数据按照一定的顺序进行排序。本文…

排序02 Multi-gate Mixture-of-Experts (MMoE)

MMoE: 不一定适合业务场景 输入向量(包含四种特征)到三个神经网络(专家),不共享参数。实践中超参数专家神经网络个数需要调,会尝试4个或者8个专家。 左边另一个神经网络softmax输出的向量,三个…

element-plus 官方表格排序问题

element-plus 官方API 默认表格排序存在问题,一个list 被多组排序 修改后: 注意点: 这里一定要使用 sortable"custom",自定义 sort-change 方法 使用 sortable true 的情况排序会冲突,出现莫名奇妙的问题…

Oracle SQL练习题,从小白到入门 - 上

从事DBA以来,越来越认识到自己SQL水平不足,想想sql语句还停留在大二寒假学习的黑马的Mysql《Mysql 十天精通》基础篇进阶篇,将近100集一天就学完了,黑马yyds。 再后来,做项目用Spring的MyBatis是真的香,练…

string类的学习(上)

string类与我们再C语言中接触到的字符串数据相似,但是做出了一些重大的提升,封装为类,实现了总多的接口,丰富了其功能,为简化了字符串的使用,那现在我们就开始深入学习string类吧。 1.什么事string类 C语言…

Java项目:155 springboot酒店管理系统(含论文+ppt+开题报告+说明文档)

作者主页:源码空间codegym 简介:Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 ​ 后台: 1.登录:输入账号、密码,即可登录。 2.套房管理:可对房间房型进行管理。 3.入住管…

elk部署安装

elk部署 前提准备1、elasticsearch2、kibana3、logstash 前提准备 1、提前装好docker docker-compose相关命令 2、替换docker仓库地址国内镜像源 cd /etc/docker vi daemon.json # 替换内容 {"registry-mirrors": [ "https://docker.1panel.dev", "ht…

L1练习-鸢尾花数据集处理(分类/聚类)

背景 前文(《AI 自学 Lesson1 - Sklearn(开源Python机器学习包)》)以鸢尾花数据集的处理为例,本文将完善其代码,在使用 sklearn 的部分工具包基础上,增加部分数据预处理、数据分析和数据可视化…

FL Studio 2024 发布,添加 FL Cloud 插件、AI 等功能

作为今年最受期待的音乐制作 DAW 更新之一,FL Studio 2024发布引入了新功能,同时采用了新的命名方式,从现在起将把发布年份纳入其名称中。DAW 的新增功能包括在 FL Cloud 中添加插件、AI 驱动的音乐创作工具和 FL Studio 的新效果。 FL Clou…

Java 解决阿里云OSS服务器私有权限图片通过URL无法预览的问题

简单描述一下此场景的业务: 由于系统中需要将上传的图片在系统中展示(private私有权限不能直接通过url直接展示),不想通过先下载下来然后以流的形式返回给前台展示这种方法很不友好,毕竟现在前台展示方式都是通过图片URL进行展示,所以就上官网查看API文档,果然找到了解决…

视频美颜平台是如何搭建的?基于直播美颜SDK源码的开发技术详解

今天,笔者将详细讲解如何基于直播美颜SDK源码搭建视频美颜平台的技术路径。 一、理解视频美颜技术 视频美颜技术主要通过图像处理算法对视频流进行实时处理,包括肤色优化、瑕疵修复、面部特征增强等。实现这一目标需要高效的图像处理算法和稳定的实时渲…

电脑异常情况总结

文章目录 笔记本无症状息屏黑屏 笔记本无症状息屏黑屏 🍎 问题描述: 息屏导致黑屏;依次操作计算机--》右键--》管理--》事件查看器--》Windows日志--》系统;从息屏到异常黑屏之间出现了很多错误,如下:事件…

大规模创新类竞赛评审方案的建模与研究

随着科技的发展和教育制度的改革,近年来涌现出一批以“创新”为主题的竞赛项目。这类竞赛的运行模式为,参赛队伍提交文档、视频或幻灯片等文本形式的作品,专家对参赛队伍提交的作品评阅判分,一份作品将由多位专家独立进行评阅打分…

WPF入门_04绑定

WPF绑定使得原本需要多行代码实现的功能,现在只需要简单的XAML代码就可以完成之前多行后台代码实现的功能。WPF绑定可以理解为一种关系,该关系告诉WPF从一个源对象提取一些信息,并将这些信息来设置目标对象的属性。 目标属性总是依赖属性。然而,源对象可以是任何内容,可以…

mysql8以上版本第一次下载后的登录问题

mysql8以上版本第一次下载后的登录问题 在官网下载mysql后,按照MySQL下载和安装教程操作就可以 如果出现问题,参考https://blog.csdn.net/weixin_63107823/article/details/136588474 注意ini配置文件,如果你是复制的别人的代码&#xff0…

一些简单的编程题(Java与C语言)

引言: 这篇文章呢,小编将会举一些简单的编程题用来帮助大家理解一下Java代码,并且与C语言做个对比,不过这篇文章所出现的题目小编不会向随缘解题系列里面那样详细的讲解每一到题,本篇文章的主要目的是帮助小编和读者们…

算法魅力-双指针的实战

目录 1.双指针的介绍 1. 左右指针(对撞指针) 2. 快慢指针 2.题目练习讲解 2.1 移动零 算法思路 代码展示 画图效果效果 2.2 复写零 算法思路 代码展示 2.3 快乐数 算法思路 代码展示 2.4 盛最多水的容器 算法思路 代码展示 结束语 1.双指针的…