1.sparkexecutorԴ??
2.Spark源码解析2-YarnCluster模式启动
3.大数据面试题-Spark的内存模型
4.Sparkåç | å
å管ç
sparkexecutorԴ??
对于Spark新手和有经验的开发者来说,理解Spark的术语是提高沟通效率的关键。本文将通过解析Spark的运行机制,结合WordCount案例,逐步介绍核心概念。
Spark运行的潇湘联盟源码核心框架包括SparkContext、Cluster Manager和Executor。Cluster Manager,如YARN、Spark Standalone或Mesos,负责资源的统一管理和调度。每个工作节点上的Executor是一个独立的JVM进程,负责执行分配的任务,内部包含多个并发执行的Task线程和内存空间。
Spark的运行流程可以分为几个步骤:首先,driver(用户编写的Spark程序)创建SparkContext或SparkSession,并与Cluster Manager通信,将任务分解成Job。Job由一系列Stage组成,Stage之间的网聊源码执行是串行的,由shuffle、reduceBy和save等操作触发。Task是Stage的基本执行单元,一个Stage可以包含多个Task,每个Task处理数据的一部分。
Partition是数据源的切分,RDD(分布式弹性数据集)由多个partition组成,用于并行执行任务。当我们提交Spark job时,它会被拆分成多个Stage和Task,然后发送到Executor执行。每个Stage的执行结果会汇总到Driver,最后所有节点的数据在Master节点上聚合,生成性能指标。
部署模式,如Standalone、YARN或Mesos,决定了Cluster Manager的类型。运行模式则指Driver运行的eros源码位置,Client模式下Driver在提交任务的机器上,而Cluster模式下Driver在集群中。在实际的WordCount示例中,YARN部署模式下,只有一个collect操作,导致一个Job被划分为三个Stage,每个Stage的执行依赖关系清晰可见。
通过理解这些术语,开发者可以更准确地描述Spark应用程序的执行过程。希望本文能帮助你更好地掌握Spark的术语,提升开发效率。如果你对大数据或人工智能领域感兴趣,不妨关注我获取更多内容。
Spark源码解析2-YarnCluster模式启动
YARN 模式运行机制主要体现在Yarn Cluster 模式和Yarn Client 模式上。在Yarn Cluster模式下,SparkSubmit、ApplicationMaster 和 CoarseGrainedExecutorBackend 是独立的进程,而Driver 是独立的线程;Executor 和 YarnClusterApplication 是对象。在Yarn Client模式下,ocq源码SparkSubmit、ApplicationMaster 和 YarnCoarseGrainedExecutorBackend 也是独立的进程,而Executor和Driver是对象。
在源码中,SparkSubmit阶段首先执行Spark提交命令,底层执行的是开启SparkSubmit进程的命令。代码中,SparkSubmit从main()开始,根据运行模式获取后续要反射调用的类名赋给元组中的ChildMainClass。如果是Yarn Cluster模式,则为YarnClusterApplication;如果是Yarn Client模式,则为主类用户自定义的类。接下来,获取ChildMainClass后,通过反射调用main方法的过程,反射获取类然后通过构造器获取一个示例并多态为SparkApplication,再调用它的start方法。随后调用YarnClusterApplication的start方法。在YarnClient中,飞艇源码new一个Client对象,其中包含了yarnClient = YarnClient.createYarnClient属性,这是Yarn在SparkSubmit中的客户端,yarnClient在第行初始化和开始,即连接Yarn集群或RM。之后就可以通过这个客户端与Yarn的RM进行通信和提交应用,即调用run方法。
ApplicationMaster阶段主要涉及开启一个Driver新线程、AM向RM注册、AM向RM申请资源并处理、封装ExecutorBackend启动命令以及AM向NM通信提交命令由NM启动ExecutorBackend。在ApplicationMaster进程中,首先开启Driver线程,开始运行用户自定义代码,创建Spark程序入口SparkContext,接着创建RDD,生成job,划分阶段提交Task等操作。
在申请资源之前,AM主线程创建了Driver的终端引用,作为参数传入createAllocator(),因为Executor启动后需要向Driver反向注册,所以启动过程必须封装Driver的EndpointRef。AM主线程向RM申请获取可用资源Container,并处理这些资源。ExecutorBackend阶段尚未完成,后续内容待补充。
大数据面试题-Spark的内存模型
面试题来源:可回答:1)Spark内存管理的结构;2)Spark的Executor内存分布(参考“内存空间分配”)
1、堆内和堆外内存规划
作为一个JVM 进程,Executor 的内存管理建立在JVM的内存管理之上,Spark对JVM的堆内(On-heap)空间进行了更为详细的分配,以充分利用内存。同时,Spark引入了堆外(Off-heap)内存,使之可以直接在工作节点的系统内存中开辟空间,进一步优化了内存的使用。
堆内内存受到JVM统一管理,堆外内存是直接向操作系统进行内存的申请和释放。
默认情况下,Spark 仅仅使用了堆内内存。Executor 端的堆内内存区域大致可以分为以下四大块:堆内内存的大小,由Spark应用程序启动时的 –executor-memory 或 spark.executor.memory 参数配置。这些任务在缓存 RDD 数据和广播(Broadcast)数据时占用的内存被规划为存储(Storage)内存,而这些任务在执行 Shuffle 时占用的内存被规划为执行(Execution)内存,剩余的部分不做特殊规划。
Spark对堆内内存的管理是一种逻辑上的”规划式”的管理。不同管理模式下,这三部分占用的空间大小各不相同。
堆外内存意味着把内存对象分配在Java虚拟机的堆以外的内存,这些内存直接受操作系统管理。这样做的结果就是能保持一个较小的堆,以减少垃圾收集对应用的影响。
利用JDK Unsafe API(从Spark 2.0开始),Spark 可以直接操作系统堆外内存,减少了不必要的内存开销,以及频繁的 GC 扫描和回收,提升了处理性能。堆外内存可以被精确地申请和释放,而且序列化的数据占用的空间可以被精确计算,所以相比堆内内存来说降低了管理的难度,也降低了误差。
在默认情况下堆外内存并不启用,可通过配置 spark.memory.offHeap.enabled 参数启用,并由 spark.memory.offHeap.size 参数设定堆外空间的大小。除了没有 other 空间,堆外内存与堆内内存的划分方式相同,所有运行中的并发任务共享存储内存和执行内存。
2、内存空间分配
静态内存管理与统一内存管理的区别在于存储内存和执行内存共享同一块空间,可以动态占用对方的空闲区域。
统一内存管理的堆内内存结构如图所示:其中最重要的优化在于动态占用机制。统一内存管理的堆外内存结构如下图所示。
凭借统一内存管理机制,Spark 在一定程度上提高了堆内和堆外内存资源的利用率,降低了开发者维护 Spark 内存的难度,但并不意味着开发者可以高枕无忧。如果存储内存的空间太大或者说缓存的数据过多,反而会导致频繁的全量垃圾回收,降低任务执行时的性能。
3、存储内存管理
RDD的持久化机制
弹性分布式数据集(RDD)作为 Spark 最根本的数据抽象,是只读的分区记录(Partition)的集合。RDD的持久化由 Spark的Storage模块负责,实现了RDD与物理存储的解耦合。Storage模块负责管理Spark在计算过程中产生的数据,将那些在内存或磁盘、在本地或远程存取数据的功能封装了起来。在具体实现时Driver端和 Executor 端的Storage模块构成了主从式的架构。
在对RDD持久化时,Spark规定了MEMORY_ONLY、MEMORY_AND_DISK 等7种不同的存储级别,而存储级别是以下5个变量的组合。
通过对数据结构的分析,可以看出存储级别从三个维度定义了RDD的 Partition(同时也就是Block)的存储方式。
4、执行内存管理
执行内存主要用来存储任务在执行Shuffle时占用的内存。
若在map端选择普通的排序方式,会采用ExternalSorter进行外排,在内存中存储数据时主要占用堆内执行空间。
若在map端选择 Tungsten 的排序方式,则采用ShuffleExternalSorter直接对以序列化形式存储的数据排序,在内存中存储数据时可以占用堆外或堆内执行空间,取决于用户是否开启了堆外内存以及堆外执行内存是否足够。
在Shuffle Write 阶段中用到的Tungsten是Databricks公司提出的对Spark优化内存和CPU使用的计划。在Shuffle过程中,Spark会根据Shuffle的情况来自动选择是否采用Tungsten排序。
Tungsten 采用的页式内存管理机制建立在MemoryManager之上,即 Tungsten 对执行内存的使用进行了一步的抽象,这样在 Shuffle 过程中无需关心数据具体存储在堆内还是堆外。每个内存页用一个MemoryBlock来定义,并用 Object obj 和 long offset 这两个变量统一标识一个内存页在系统内存中的地址。
Sparkåç | å å管ç
Sparkä½ä¸ºä¸ä¸ªåºäºå åçåå¸å¼è®¡ç®å¼æï¼å ¶å å管ç模åå¨æ´ä¸ªç³»ç»ä¸æ®æ¼çé常éè¦çè§è²ã
å¨æ§è¡Sparkçåºç¨ç¨åºæ¶ï¼Sparké群ä¼å¯å¨DriveråExecutor两ç§JVMè¿ç¨ï¼
Spark管ççå å主è¦åå为4个åºåï¼
Executorä½ä¸ºä¸ä¸ªJVMè¿ç¨ï¼å®çå å管ç建ç«å¨JVMçå å管çä¹ä¸ï¼Spark对JVMçå å ï¼On-heapï¼ç©ºé´è¿è¡äºæ´ä¸ºè¯¦ç»çåé ï¼ä»¥å åå©ç¨å åãåæ¶ï¼Sparkå¼å ¥äºå å¤ï¼Off-heapï¼å åï¼ä½¿ä¹å¯ä»¥ç´æ¥å¨å·¥ä½èç¹çç³»ç»å åä¸å¼è¾ç©ºé´ï¼è¿ä¸æ¥ä¼åäºå åç使ç¨ã
å å å åç大å°ï¼ç± Spark åºç¨ç¨åºå¯å¨æ¶ç executor-memory æ spark.executor.memory åæ°é ç½®ãExecutor å è¿è¡ç并åä»»å¡å ±äº« JVM å å å åï¼è¿äºä»»å¡å¨ç¼å RDD æ°æ®å广æï¼Broadcastï¼æ°æ®æ¶å ç¨çå å被è§å为åå¨ï¼Storageï¼å åï¼èè¿äºä»»å¡å¨æ§è¡ Shuffle æ¶å ç¨çå å被è§å为æ§è¡ï¼Executionï¼å åï¼å©ä½çé¨åä¸åç¹æ®è§åï¼é£äº Spark å é¨ç对象å®ä¾ï¼æè ç¨æ·å®ä¹ç Spark åºç¨ç¨åºä¸ç对象å®ä¾ï¼åå ç¨å©ä½ç空é´ãä¸åç管ç模å¼ä¸ï¼è¿ä¸é¨åå ç¨ç空é´å¤§å°åä¸ç¸åã
Spark 对å å å åç管çæ¯ä¸ç§é»è¾ä¸ç"è§åå¼"ç管çï¼å 为对象å®ä¾å ç¨å åçç³è¯·åéæ¾é½ç± JVM å®æï¼Spark åªè½å¨ç³è¯·ååéæ¾åè®°å½è¿äºå åï¼æ们æ¥çå ¶å ·ä½æµç¨ï¼
为äºè¿ä¸æ¥ä¼åå åç使ç¨ä»¥åæé« Shuffle æ¶æåºçæçï¼Spark å¼å ¥äºå å¤ï¼Off-heapï¼å åï¼ä½¿ä¹å¯ä»¥ç´æ¥å¨å·¥ä½èç¹çç³»ç»å åä¸å¼è¾ç©ºé´ï¼åå¨ç»è¿åºååçäºè¿å¶æ°æ®ãå©ç¨ JDK Unsafe APIï¼ä» Spark 2.0 å¼å§ï¼ï¼å¨ç®¡çå å¤çåå¨å åæ¶ä¸ååºäº Tachyonï¼èæ¯ä¸å å¤çæ§è¡å åä¸æ ·ï¼åºäº JDK Unsafe API å®ç°ï¼Spark å¯ä»¥ç´æ¥æä½ç³»ç»å å¤å åï¼åå°äºä¸å¿ è¦çå åå¼éï¼ä»¥åé¢ç¹ç GC æ«æååæ¶ï¼æåäºå¤çæ§è½ãå å¤å åå¯ä»¥è¢«ç²¾ç¡®å°ç³è¯·åéæ¾ï¼èä¸åºååçæ°æ®å ç¨ç空é´å¯ä»¥è¢«ç²¾ç¡®è®¡ç®ï¼æ以ç¸æ¯å å å åæ¥è¯´éä½äºç®¡ççé¾åº¦ï¼ä¹éä½äºè¯¯å·®ã
å¨é»è®¤æ åµä¸å å¤å å并ä¸å¯ç¨ï¼å¯éè¿é ç½® spark.memory.offHeap.enabled åæ°å¯ç¨ï¼å¹¶ç± spark.memory.offHeap.size åæ°è®¾å®å å¤ç©ºé´ç大å°ãé¤äºæ²¡æ other 空é´ï¼å å¤å åä¸å å å åçååæ¹å¼ç¸åï¼ææè¿è¡ä¸ç并åä»»å¡å ±äº«åå¨å ååæ§è¡å åã
Spark 1.6 ä¹åé»è®¤ä¸ºç»ä¸ç®¡çï¼UnifiedMemoryManagerï¼æ¹å¼ï¼1.6 ä¹åéç¨çéæ管çï¼StaticMemoryManagerï¼æ¹å¼ä»è¢«ä¿çï¼å¯éè¿é ç½® spark.memory.useLegacyMode=true åæ°å¯ç¨éæå å管çæ¹å¼ãä¸é¢æ们ä»ç»ä¸ä¸¤ç§å å管ç模åçè¿åã
å¨ Spark æåéç¨çéæå å管çæºå¶ä¸ï¼åå¨å åãæ§è¡å ååå ¶ä»å åç大å°å¨ Spark åºç¨ç¨åºè¿è¡æé´å为åºå®çï¼ä½ç¨æ·å¯ä»¥åºç¨ç¨åºå¯å¨åè¿è¡é ç½®ï¼å å å åçåé å¦ä¸æ示ï¼
Spark 1.6 ä¹åå¼å ¥çç»ä¸å å管çæºå¶ï¼ä¸éæå å管ççåºå«å¨äºåå¨å ååæ§è¡å åå ±äº«åä¸å空é´ï¼å¯ä»¥å¨æå ç¨å¯¹æ¹ç空é²åºåãå¦ä¸å¾æ示ï¼
å ¶ä¸æéè¦çä¼åå¨äºå¨æå ç¨æºå¶ï¼å ¶è§åå¦ä¸ï¼
æ°ççæ¬å¼å ¥äºæ°çé 置项ï¼
ååç»ä¸å å管çæºå¶ï¼Spark å¨ä¸å®ç¨åº¦ä¸æé«äºå å åå å¤å åèµæºçå©ç¨çï¼éä½äºå¼åè ç»´æ¤ Spark å åçé¾åº¦ï¼ä½å¹¶ä¸æå³çå¼åè å¯ä»¥é«ææ 忧ãè¬å¦ï¼æ以å¦æåå¨å åç空é´å¤ªå¤§æè 说ç¼åçæ°æ®è¿å¤ï¼åèä¼å¯¼è´é¢ç¹çå ¨éåå¾åæ¶ï¼éä½ä»»å¡æ§è¡æ¶çæ§è½ï¼å 为ç¼åç RDD æ°æ®é常é½æ¯é¿æé©»çå åçãæ以è¦æ³å ååæ¥ Spark çæ§è½ï¼éè¦å¼åè è¿ä¸æ¥äºè§£åå¨å ååæ§è¡å ååèªç管çæ¹å¼åå®ç°åçã