8.1 计算引擎概述
Spark的计算引擎主要包括执行内存和Shuffle两部分
1、执行内存
执行内存只要包括执行内存、任务内存管理器、内存消费者等内容。
执行内存包括在JVM堆上进行分配的执行内存池和在操作系统的内存中进行分配的Tungsten。内存管理器将提供API对执行内存和Tungsten进行管理(包括申请内存、释放内存等)。因为同一节点上能够运行多次任务尝试,所有需要每一次任务尝试都有单独的任务内存管理器为其服务。任务尝试通过任务内存管理器与内存管理器交互,以申请任务尝试所需要的执行内存,并在任务尝试结束后释放使用的执行内存。一次任务尝试过程中会有多个组件需要使用执行内存,这些组件统称为内存消费者。消费者需要的执行内存都是向任务内存管理器所申请的。
2、什么是Shuffle
Shuffle是所有MR计算框架必须面临的执行阶段,Shuffle用于打通map任务的输出和reduce任务的输入,map任务的中间输出结果按照指定的分区策略分配给处理某个分区的reduce任务。
经过了以上优化,目前Spark实现的Shuffle的过程大致为:map任务在输出时会进行分区计算并生成数据文件和索引文件等步骤,可能还伴随有缓存、排序、聚合、溢出、合并等操作。reduce任务将map任务输出的Block划分为本地和远端的Block,对于远端的Block,需要ShuffleClient从远端节点下载,而对于本地的Block,只需要从本地的存储体系中读取即可。reduce任务读取到map任务输出的数据后,可能进行缓存、排序、聚合、溢出、合并等操作,最终输出结果
8.2 内存管理器与执行内存
1、ExecutorMemoryPool详解
ExecutorMemoryPool的方法:
1)memoryUsed:已经使用的内存大小
2)getMemoryUsageForTask:获取任务尝试使用的内存大小
3)acquireMemory:用于给taskAttemptId对应的任务尝试获取指定大小(即numBytes)的内存
4)releaseMemory:用于给taskAttemptId对应的任务尝试释放指定大小的内存
5)releaseAllMemoryForTask:用于释放taskAttemptId对应的任务尝试所消费的所有内存
8.2.2 MemoryManager模型与执行内存
1)acquireExecutionMemory:为执行taskAttemptId对应的任务尝试,从堆内存或堆外内存获取所需大小(即numBytes)的内存
2)releaseExecutionMemory:从堆内存或堆外内存释放taskAttemptId对应的任务尝试所消费的指定大小(即numBytes)执行内存
3)releaseAllExecutionMemoryForTask:从堆内存及堆外内存释放taskAttemptId代表的任务尝试所消费的所有执行内存。
4)executionMemoryUsed:获取堆上执行内存池与堆外执行内存池已经使用的执行内存之和
5)getExecutionMemoryUsageForTask:获取taskAttemptId代表的任务尝试在堆上执行内存池与堆外执行内存池所消费的执行内存之和。
8.2.3 UnifiedMemoryManager与执行内存
根据acquireExecutionMemory方法可以得知:
如果存储内存突破了存储内存与执行内存的软边界,则执行内存只能回收被借用的内存
如果存储内存没有突破存储内存与执行内存的软边界,则执行内存不但能够回收被借用的内存,还可以向存储内存借用一部分空闲内存。
总得来说:存储内存的优先级 > 执行内存。
8.3 内存管理器与Tungsten
Tungsten使用sun.misc.Unsafe的API直接操作系统内存,避免了在JVM中加载额外的Class ,也不用创建额外的对象,因而减少了不必要的内存开销,降低了GC扫描和回收的频率,提升了处理性能。堆外内存可以被精确地申请和释放,而且序列化的数据占用的空间可以被精确的计算,所以相对堆内存来说降低了管理的难度,也降低了误差。
8.3.1 MemoryBlock详解
操作系统中的Page是一个内存块,在Page中可以存放数据,操作系统中会有多种不同的Page。操作系统对数据的读取,往往是先确定数据所在的Page,然后使用Page的偏移量和所读数据的长度从Page中读取数据。
在Tungsten中实现了一种与操作系统的内存Page非常相似的数据结构,这个对象就是MemoryBlock。MemoryBlock中的数据可能位于JVM的堆上,也可能位于JVM的堆外内存(操作系统内存)中。
Tungsten处于堆内存模式时,首先从堆内找到对象,然后使用offset定位数据的位置,当Tungsten处于堆外内存模式时,则直接使用offset从堆外内存中定位。
MemoryBlock中提供的三个方法:
1)size:MemoryBlock的大小,即length
2)fromLongArray:创建一个指向由长整型使用的内存的MemoryBlock
3)fill:以指定的字节填写整个MemoryBlock,即将obj对象从offset开始,长度为length的堆内存替换为指定字节的值。
8.3.2 MemoryManager模型与Tungsten
MemoryManager中除了存储内存和执行内存外,还定义了几个与Tungsten优化相关的常量
1)tungstenMemoryMode:Tungsten的内存模式
2)pageSizeBytes:Tungsten采用的Page的默认大小
3)tungstenMemoryAllocat