转载:http://www.cnblogs.com/jcchoiling/p/6494652.htmlhtml
Spark 从1.6.x 开始对 JVM 的内存使用做出了一种全新的改变,Spark 1.6.x 之前是基于静态固定的JVM内存使用架构和运行机制,若是你不知道 Spark 到底对 JVM 是怎么使用,你怎么能够颇有信心地或者是彻底肯定地掌握和控制数据的缓存空间呢,因此掌握Spark对JVM的内存使用内幕是相当重要的。不少人对 Spark 的印象是:它是基于内存的,并且能够缓存一大堆数据,显现 Spark 是基于内存的观点是错的,Spark 只是优先充分地利用内存而已。若是你不知道 Spark 能够缓存多少数据,你就误乱地缓存数据的话,确定会有问题。算法
在数据规模已经肯定的状况下,你有多少 Executor 和每一个 Executor 可分配多少内存 (在这个物理硬件已经肯定的状况下),你必须清楚知道你的內存最多可以缓存多少数据;在 Shuffle 的过程当中又使用了多少比例的缓存,这样对于算法的编写以及业务实现是相当重要的!!!缓存
文章的后部份会介绍 Spark 2.x 版本 JVM 的内存使用比例,它被称之为 Spark Unified Memory,这是统一或者联合的意思,可是 Spark 没有用 Shared 这个字,由于 A 和 B 进行 Unified 和 A 和 B 进行 Shared 实际上是两个不一样的概念, Spark 在运行的时候会有不一样类型的 OOM,你必须搞清楚这个 OOM 背后是由什么致使的。 好比说咱们使用算子 mapPartition 的时候,通常会建立一些临时对象或者是中间数据,你这个时候使用的临时对象和中间数据,是存储在一个叫 UserSpace 里面的用户操做空间,那你有没有想过这个空间的大小会致使应用程序出现 OOM 的状况,在 Spark 2.x 中 Broadcast 的数据是存储在什么地方;ShuffleMapTask 的数据又存储在什么地方,可能你会认为 ShuffleMapTask 的数据是缓存在 Cache 中。这篇文章会介绍 JVM 在 Spark 1.6.X 之前和 2.X 版本对 Java 堆的使用,还会逐一解密上述几个疑问,也会简单介绍 Spark 1.6.x 之前版本在 Spark On Yarn 上内存的使用案例,但愿这篇文章能为读者带出如下的启发: 安全
JVM 有不少不一样的区,最开始的时候,它会经过类装载器把类加载进来,在运行期数据区中有 "本地方法栈","程序计数器","Java 栈"、"Java 堆"和"方法区"以及本地方法接口和它的本地库。从 Spark 的角度来谈代码的运行和数据的处理,主要是谈 Java 堆 (Heap) 空间的运用。架构
一、Spark JVM 到底能够缓存多少数据并发
下图显示的是Spark 1.6.x 之前版本对 Java 堆 (heap) 的使用状况,左则是 Storage 对内存的使用,右则是 Shuffle 对内存的使用,这叫 StaticMemoryManagement,数据处理以及类的实体对象都存放在 JVM 堆 (heap) 中。spa
二、Spark 1.6.x 版本对 JVM 堆的使用线程
JVM Heap 默认状况下是 512MB,这是取决于 spark.executor.memory 的参数,在回答 Spark JVM 到底能够缓存多少数据这个问题以前,首先了解一下 JVM Heap 在 Spark 中是如何分配内存比例的。不管你定义了 spark.executor.memory 的内存空间有多大,Spark 必然会定义一个安全空间,在默认状况下只会使用 Java 堆上的 90% 做为安全空间,在单个 Executor 的角度来说,就是 Heap Size x 90%。htm
埸景一:假设说在一个Executor,它可用的 Java Heap 大小是 10G,实际上 Spark 只能使用 90%,这个安全空间的比例是由 spark.storage.safetyFaction 来控制的。(若是你内存的 Heap 很是大的话,能够尝试调高为 95%),在安全空间中也会划分三个不一样的空间:一个是 Storage 空间、一个是 Unroll 空间和一个是 Shuffle 空间。对象
安全空间 (safe):计算公式是 spark.executor.memory x spark.storage.safetyFraction。也就是 Heap Size x 90%,在埸景一的例子中是 10 x 0.9 = 9G;
缓存空间 (Storage):计算公式是 spark.executor.memory x spark.storage.safetyFraction x spark.storage.memoryFraction。也就是 Heap Size x 90% x 60%;Heap Size x 54%,在埸景一的例子中是 10 x 0.9 x 0.6 = 5.4G;一个应用程序能够缓存多少数据是由 safetyFraction 和 memoryFraction 这两个参数共同决定的。
Unroll 空间:
计算公式是 spark.executor.memory x spark.storage.safetyFraction x spark.storage.memoryFraction x spark.storage.unrollFraction
也就是 Heap Size x 90% x 60% x 20%;Heap Size x 10.8%,在埸景一的例子中是 10 x 0.9 x 0.6 x 0.2 = 1.8G,你可能把序例化后的数据放在内存中,当你使用数据时,你须要把序例化的数据进行反序例化。
对 cache 缓存数据的影响是因为 Unroll 是一个优先级较高的操做,进行 Unroll 操做的时候会占用 cache 的空间,并且又能够挤掉缓存在内存中的数据 (若是该数据的缓存级别是 MEMORY_ONLY 的话,不然该数据会丢失)。
Shuffle 空间:
计算公式是 spark.executor.memory x spark.shuffle.memoryFraction x spark.shuffle.safteyFraction。在 Shuffle 空间中也会有一个默认 80% 的安全空间比例,因此应该是 Heap Size x 20% x 80%;Heap Size x 16%,在埸景一的例子中是 10 x 0.2 x 0.8 = 1.6G;从内存的角度讲,你须要从远程抓取数据,抓取数据是一个 Shuffle 的过程,好比说你须要对数据进行排序,显如今这个过程当中须要内存空间。
下图是一种叫联合内存 (Spark Unified Memeory),数据缓存与数据执行之间的内存能够相互移动,这是一种更弹性的方式,下图显示的是 Spark 2.x 版本对 Java 堆 (heap) 的使用状况,数据处理以及类的实体对象存放在 JVM 堆 (heap) 中。