IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> 13,spark内存管理 -> 正文阅读

[大数据]13,spark内存管理

Driver和Executor都是Jvm进程,运行于yarn/k8s中,因此Spark内存管理会涉及Driver端和Executor这两种进程中内存的申请和回收操作。

Driver端和Executor端都有自己的内存空间,内存管理统一由MemoryManager统一管理。
在这里插入图片描述

统一内存管理

在Spark1.6之前,采用的是静态内存管理(StaticMemoryManager), 从1.6开始默认采用统一内存管理(UnifiedMemoryManager). 相比静态内存管理方式,统一内存管理方式中存储和计算内存能够共享同一空间,并且可以动态使用彼此的空闲区域。一下我们以统一内存管理来说。
Memory将内存模式分为堆内(ON_HEAP) 和堆外(OFF_HEAP)。

堆内内存

因为Executor的运行于Jvm之上,对象实例占用内存的申请和释放都由Jvm完成,只能在申请和释放后记录这些内存。因此 Spark对堆内内存的管 理只是在逻辑上进行记录和规划。

在 JVM 中,对象可以以序列化的方式存储, 在访问时需要进行序 列化的逆过程一一反序列化 , Spark 中序列化的对象是字节流的形式,其占用的内存大小可直接计 算,而对于反序列化的对象,其占用的内存是通过周期性地采样近似估算而得的,并不是每次 新增的数据项都会计算一次占用的内存大小,这种方法降低了时间开销,但是有可能误差较大,因此可能导致某一时刻的实际内存可能远远超出预期。

堆内内存依赖于 JVM,无法完全摆脱 GC 带来的开销, 在被Spark标记为释放的对象实例,很有可能在实际上并没有被JVM回收,导致实际可用的内存小于Spark记录的可用内存。所以Spark并不能准确记录实际可用的堆内内存,从而也就无法完全避免内存溢出(OOM)的异常。

Spark通过对存储内存和执行内存各自独立的规划管理,可以决定是否要在存储内存里缓存新的RDD,以及是否为新的任务分配执行内存,在一定程度上可以提升内存的利用率,减少异常的出现。

堆外内存

不在 JVM 内申请内存,而是调用 Java 的 unsafe 相关 API 进行申请,可以避免频繁的GC, 堆外内存可以被精确地申请和释放,而且序列化的数据占用的空间可以被精确计算,所以相比堆内内存来说降低了管理的难度。**
为了进一步优化内存的使用以及提高Shuffle时排序的效率,Spark引入了堆外(Off-heap)内存。使之可以直接在工作节点的系统内存中开辟空间,存储经过序列化的二进制数据。

spark官方建议谨慎使用堆外内存,因为堆内和堆外不互通,tungsten对堆内的优化足以应付。

统一内存模型

堆内内存模型

在堆内内存中,MemoryManager将内存分为存储内存,执行内存,其他,预留内存。

在这里插入图片描述

堆外内存模型

在堆外内存中,MemoryManager将内存分为存储内存,执行内存。而堆外内存的开启方式由spark.unsafe.offHeap=true, spark.memory.offHeap.size=2g,来管理。 Executor 中的 Execution 内存是堆内的 Execution 内存和堆外的 Execution 内存之和,同理,Storage 内存也一样。

  • spark.memory.offHeap.enabled 等价于 spark.unsafe.offHeap

  • spark.executor.memoryOverhead/ spark.driver.memoryOverhead作用于yarn/k8s上的堆外内存,是executor/driver所需要的额外的内存开销, 用来保证稳定性,主要存储nio buffer, 这部分内存在堆内和堆外都用不到,spark也用不到所以不用关系。

  • spark.memory.offHeap.size 想用堆外让spark管理数据,只有这个配置, 作用于executor的堆外内存,在spark3之前spark.executor.memoryOverhead和spark.memory.offHeap.size并没有进行区分,在spark-3.0上面又有一些差异,spark.memory.offHeap.size和spark.executor.memoryOverhead单独进行区分。
    具体可以参考:https://stackoverflow.com/questions/58666517/difference-between-spark-yarn-executor-memoryoverhead-and-spark-memory-offhea
    在这里插入图片描述

  • SystemReserved(预留内存) 系统会预留300MB内存,留出充足空间,防止OOM,

  • UnifiedMemory(统一内存):在剩余的可用内存( (JVM heap space - 300M) )中, 有spark.memory.fraction(默认0.6)会被分配到storage和Execution区域, 用于存储和计算, 其中,storage和Execution各占50%, 即默认为总堆上内存的0.6*0.5=0.3。

  • Other(其他内存): 在 (JVM heap space - 300MiB) * (1-spark.memory.fraction,默认0.4)就是Other区域, 用于进行spark内部元数据, 用户数据结构、以及在大数据情况下防止OOM错误的使用。

内存区域存储对象

堆内和堆外的execution内存和storage内存使用场景几乎一直,堆内内存因为依赖JVM的GC所以不能保证内存空间已经被回收,堆外内存因为手动进行内存的分配和释放,所以Spark能准确预估内存使用量。

堆内和堆外的内存不能互相借用。比如一个task在使用了堆外内存之后,发现堆外内存不够了,但是堆内是足够的,但是是不会借用堆内的,只能OOM.
Tungsten统一了内存管理,使用page来管理内存,这样做的目的主要是统一内存对象。对于堆内来讲page就是大对象,对于堆外来讲page是os的内存寻址,因此两块内存是不能同时使用的。

execution内存

主要用于shuffle,join, sort, aggregation计算的临时数据。

storage内存

主要存储spark的缓存数据,rdd缓存,广播变量等。

统一内存的计算逻辑

storage存储内存

jvm堆内内存 * spark.memory.fraction * spark.storage.memoryFraction

  • jvm堆内内存 = spark.executor.memory,一般而言会稍微小一点,和jvm分配有关系。
  • spark.memory.fraction 默认是0.6。 统一内存executor,storage占用的空间。其他0.4包括预留内存和其他内存,主要是为了防止OOM和用户定义的数据结构存储。
  • spark.storage.memoryFraction 默认是0.5。 存储内存占用的空间。

在线上的场景下,可以根据任务的状态设置,比如执行比例较高,就把spark.storage.memoryFraction调低, 如果gc较少,spark.memory.fraction调高,以目前各大厂商提供的机器配置,大部分场景下,限制性能主要是CPU,而不是内存,所以可以根据情况调高spark.memory.Fraction.降低spark.memory.storageFraction。

execution执行内存

jvm堆内内存 * spark.memory.fraction * (1-spark.storage.memoryFraction)

动态占用机制

统一 内存管理最大的特点在于动态占用机制,Execution 内存和 Storage 内存可以互相共享的。也就是说,如果 Execution 内存不足,而 Storage 内存有空闲,那么 Execution 可以从 Storage 中申请空间;反之亦然。其中的规则如下:

  • **双方的空间都不足时,则存储到硬盘,若己方空间不足而对方空间空余时,可借用对方的空间。
  • 执行内存的空间被存储占用后,可让存储将占用的部分转存到硬盘,然后“归还”借用的空间。
  • 存储内存的空间被执行占用后,无法让执行占用内存“归还”,因为需要考虑 Shuffle过程中的很多因素**

在这里插入图片描述

执行内存管理

Executor 内运行的任务同样共 享执行内存 。 假设当前 Executor 中正在执行的任务数目为 n,那么每个任务可占用的执行内存大小的范围为[ l/缸, 1/叫。 每个任务在启动时,要向 MemoryManager 申请最少 l/2n 的执行内存,如果不能满足要求, 则该任务被阻塞,直到有其 他任务释放了足够的执行内 存 , 该任务才能被唤醒 。 在执行期间, Executor 中活跃的任务数目 是不断变化的, Spark采用 wait和 notifyAll机制同步状态并重新计算 n 的值。

在这里插入图片描述

内存常见报错

OOM的问题通常出现在execution这块内存中,因为storage这块内存在存放数据满了之后,会直接丢弃内存中旧的数据,对性能有影响但是不会有OOM的问题

内存溢出

  • java.lang.OutOfMemoryError: GC overhead limit execeeded
  • java.lang.OutOfMemoryError: Java heap space
  • Container killed by YARN for exceeding memory limits. 1*.4 GB of 1* GB physical memory used.
  • shuffle file cannot find,
  • executor lost、
  • task lost

该类错误一般是由于Heap已达上限,Task需要更多的内存,而又得不到足够的内存而导致。因此,解决方案要从增加每个Task的内存使用量,满足任务需求 或 降低单个Task的内存消耗量。

  • 增加单个task的内存使用量
  • 降低单个Task的内存消耗量(增加executor的并发度,降低每个task任务处理数据量)

参考

https://blog.csdn.net/pre_tender/article/details/101517789
https://zhuanlan.zhihu.com/p/354816279

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2021-10-13 11:30:47  更:2021-10-13 11:30:49 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:59:37-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码