一、Spark三种分布式部署模式:
1.1、Spark整体架构:
1.2、spark运行流程:
1、构建Spark Application的运行环境,启动SparkContext
2、SparkContext向资源管理器(可以是Standalone,Mesos,Yarn)申请运行Executor资源,并启动StandaloneExecutorbackend。
3、Executor向SparkContext申请Task。
4、SparkContext将应用程序分发给Executor。
5、SparkContext构建成DAG图,将DAG图分解成Stage、将Taskset发送给Task Scheduler,最后由Task Scheduler将Task发送给Executor运行。
6、Task在Executor上运行,运行完释放所有资源。
1.3、spark运行特点:
1、每个Application获取专属的executor进程,该进程在Application期间一直驻留,并以多线程方式运行Task。这种Application隔离机制是有优势的,无论是从调度角度看(每个Driver调度他自己的任务),还是从运行角度看(来自不同Application的Task运行在不同JVM中),当然这样意味着Spark Application不能跨应用程序共享数据,除非将数据写入外部存储系统。
2、Spark与资源管理器无关,只要能够获取executor进程,并能保持相互通信就可以了。
3、提交SparkContext的Client应该靠近Worker节点(运行Executor的节点),最好是在同一个Rack里,因为Spark Application运行过程中SparkContext和Executor之间有大量的信息交换。
4、Task采用了数据本地性和推测执行的优化机制。
2.1、Spark Standalone模式:
(1)、资源调度框架是使用spark自带的。
(2)、采用Master/Slaves的典型架构,选中ZK来实现Master的HA。
(3)、架构图:
(4)、该模式中主要的节点有Client、Master、Worker节点,其中Driver既可以运行在Master节点上,也可以运行在本地的Client端。当使用提交程序的时候,使用new SparkConf.setManager("spark://bigdata111:7077")方式运行spark任务的时候,Driver是运行在本地Client端上面的。
(5)、运行过程:
spark运行的过程如下:
(1)、SparkContext连接到Master,向Master注册并申请资源(CPU Core 和Memory)。
(2)、Master根据SparkContext的资源申请要求和Worker心跳周期内报告的信息决定在哪个Worker上分配资源,然后在该Worker上获取资源,然后启动StandaloneExecutorBackend。
(3)、StandaloneExecutorBackend向SparkContext注册;
(4)、SparkContext将Applicaiton代码发送给StandaloneExecutorBackend;并且SparkContext解析Applicaiton代码,构建DAG图,并提交给DAG Scheduler分解成Stage(当碰到Action操作时,就会催生Job;每个Job中含有1个或多个Stage,Stage一般在获取外部数据和shuffle之前产生),然后以Stage(或者称为TaskSet)提交给Task Scheduler,Task Scheduler负责将Task分配到相应的Worker,最后提交给StandaloneExecutorBackend执行;
(5)、StandaloneExecutorBackend会建立Executor线程池,开始执行Task,并向SparkContext报告,直至Task完成;
(6)、所有Task完成后,SparkContext向Master注销,释放资源。
2.2、Spark Standalone-client:(1)、Standalone-client提交任务:./spark-submit --master spark://node01:7077 --deploy-mode client --class org.apache.spark.examples.SparkPi ../lib/spark-examples-1.6.0-hadoop2.6.0.jar 100
(2)、执行流程:
1.client模式提交任务后,会在客户端启动Driver进程。
2.Driver会向Master申请启动Application启动的资源。
3.资源申请成功,Driver端将task发送到worker端执行。
4.worker将task执行结果返回到Driver端。
(3)、总结:client模式适用于测试调试程序。Driver进程是在客户端启动的,这里的客户端就是指提交应用程序的当前节点。在Driver端可以看到task执行的情况。生产环境下不能使用client模式,是因为:假设要提交100个application到集群运行,Driver每次都会在client端启动,那么就会导致客户端100次网卡流量暴增的问题。(因为要监控task的运行情况,会占用很多端口,如上图的结果图)客户端网卡通信,都被task监控信息占用。
(4)、Client端作用 :Driver负责应用程序资源的申请、任务的分发、结果的回收、监控task执行情况。
2.3、Spark Standalone-cluster:
(1)、Standalone-cluster提交任务:./spark-submit --master spark://node01:7077 --deploy-mode cluster --class org.apache.spark.examples.SparkPi ../lib/spark-examples-1.6.0-hadoop2.6.0.jar 100
(2)、执行流程:
1、cluster模式提交应用程序后,会向Master请求启动Driver.(而不是启动application) 。
2、Master接受请求,随机在集群一台节点启动Driver进程。
3、Driver启动后为当前的应用程序申请资源。Master返回资源,并在对应的worker节点上发送消息启动Worker中的executor进程。
4、Driver端发送task到worker节点上执行。
5、worker将执行情况和执行结果返回给Driver端。Driver监控task任务,并回收结果。
(3)、总结:
1、当在客户端提交多个application时,Driver会在Woker节点上随机启动,这种模式会将单节点的网卡流量激增问题分散到集群中。在客户端看不到task执行情况和结果。要去webui中看。
2、cluster模式适用于生产环境
3、Master模式先启动Driver,再启动Application。
3.1、Spark On Yarn-client:
(1)、Yarn-Client模式中,Driver在客户端本地运行,这种模式可以使得Spark Application和客户端进行交互,因为Driver在客户端,所以可以通过webUI访问Driver的状态,默认是http://hadoop1:4040访问,而YARN通过http:// hadoop1:8088访问。
(2)、运行具体流程: (1)、Spark Yarn Client向YARN的ResourceManager申请启动Application Master。同时在SparkContent初始化中将创建DAGScheduler和TASKScheduler等,由于我们选择的是Yarn-Client模式,程序会选择YarnClientClusterScheduler和YarnClientSchedulerBackend;
(2)、ResourceManager收到请求后,在集群中选择一个NodeManager,为该应用程序分配第一个Container,要求它在这个Container中启动应用程序的ApplicationMaster,与YARN-Cluster区别的是在该ApplicationMaster不运行SparkContext,只与SparkContext进行联系进行资源的分派;
(3)、Client中的SparkContext初始化完毕后,与ApplicationMaster建立通讯,向ResourceManager注册,根据任务信息向ResourceManager申请资源(Container);
(4)、一旦ApplicationMaster申请到资源(也就是Container)后,便与对应的NodeManager通信,要求它在获得的Container中启动启动CoarseGrainedExecutorBackend,CoarseGrainedExecutorBackend启动后会向Client中的SparkContext注册并申请Task;
(3)、流程图:
3.2、Spark On Yarn-cluster:
(1)、在YARN-Cluster模式中,当用户向YARN中提交一个应用程序后,YARN将分两个阶段运行该应用程序:第一个阶段是把Spark的Driver作为一个ApplicationMaster在YARN集群中先启动;第二个阶段是由ApplicationMaster创建应用程序,然后为它向ResourceManager申请资源,并启动Executor来运行Task,同时监控它的整个运行过程,直到运行完成。
(2)、运行流程:
(1)、 Spark Yarn Client向YARN中提交应用程序,包括ApplicationMaster程序、启动ApplicationMaster的命令、需要在Executor中运行的程序等;
(2)、ResourceManager收到请求后,在集群中选择一个NodeManager,为该应用程序分配第一个Container,要求它在这个Container中启动应用程序的ApplicationMaster,其中ApplicationMaster进行SparkContext等的初始化;
(3)、ApplicationMaster向ResourceManager注册,这样用户可以直接通过ResourceManage查看应用程序的运行状态,然后它将采用轮询的方式通过RPC协议为各个任务申请资源,并监控它们的运行状态直到运行结束;
(4)、一旦ApplicationMaster申请到资源(也就是Container)后,便与对应的NodeManager通信,要求它在获得的Container中启动启动CoarseGrainedExecutorBackend,CoarseGrainedExecutorBackend启动后会向ApplicationMaster中的SparkContext注册并申请Task。这一点和Standalone模式一样,只不过SparkContext在Spark Application中初始化时,使用CoarseGrainedSchedulerBackend配合YarnClusterScheduler进行任务的调度,其中YarnClusterScheduler只是对TaskSchedulerImpl的一个简单包装,增加了对Executor的等待逻辑等;
(5)、ApplicationMaster中的SparkContext分配Task给CoarseGrainedExecutorBackend执行,CoarseGrainedExecutorBackend运行Task并向ApplicationMaster汇报运行的状态和进度,以让ApplicationMaster随时掌握各个任务的运行状态,从而可以在任务失败时重新启动任务;
(6)、 应用程序运行完成后,ApplicationMaster向ResourceManager申请注销并关闭自己。
(3)、流程图:
3.3、两种模式的区别:
1、两种模式:第一种是spark on client,第二种是spark on cluster。
2、Application Master:在YARN中,每个Application实例都有一个ApplicationMaster进程,它是Application启动的第一个容器。它负责和ResourceManager打交道并请求资源,获取资源之后告诉NodeManager为其启动Container。3、yarn-client:Application Master仅仅向YARN请求Executor,Client会和请求的Container通信来调度他们工作,也就是说Client不能离开。
4、yarn-cluster:Driver运行在AM(Application Master)中,它负责向YARN申请资源,并监督作业的运行状况。当用户提交了作业之后,就可以关掉Client,作业会继续在YARN上运行,因而YARN-Cluster模式不适合运行交互类型的作业。
4.1、Spark On Mesos:https://blog.csdn.net/qq_15300683/article/details/80933987
二、Spark中的常用术语及解释:
1、Application:用户编写的spark的程序,其中包括一个Driver功能的代码块和分布在集群中多个节点上运行的Executor代码。
2、Driver:运行上述的Application的main函数并创建SparkContext,目的是为了准备spark的运行环境,在spark中有SparkContext负责和ClusterManager通信,进行资源的申请、任务的分配和监控等,当Exectutor运行完毕的时候,负责把SparkContext关闭。
3、Executor:某个Application运行在Worker节点的一个进程,该进程负责某些Task,并且负责将数据存到内存或磁盘上,每个Application都有各自独立的一批Executor,在Spark on yarn模式下,该进程被称为CoarseGrainedExecutor Backend。一个CoarseGrainedExecutor Backend有且仅有一个Executor对象,负责将Task包装成taskRuuner,并从线程池中抽取一个空闲线程运行Task,每一个CoarseGrainedExecutor Backend能够运行的Task数量取决于cpu数量。
4、Cluster Manager:指的是在集群上获取资源的外部服务,目前有三种类型:
(1)、Sparkalone:spark的原生的资源管理,由Master负责资源的分配。
(2)、Apache Mesos:与Hadoop MR兼容性良好的一种资源调度框架。
(3)、Hadoop Yarn:只要指yarn中的ResourceManager。
5、Worker:集群中可以运行Application代码的节点,在sparkstandalone模式中是通过slave文件配置的worker节点,在Spark on yarn模式下就是NodeManager节点。
6、Task:被送到某个Executor上的工作单元,和HadoopMR中的MapTask、ReduceTask概念一样,是运行Application的基本单位。多个Task组成一个Stage,而Task的调度和管理等是由TaskScheduler负责。
7、Job:包含多个Task组成的并行计算,往往由Spark Action触发生成,一个Application中往往会产生多个Job
8、Stage:每个job会被拆分成多组Task,作为一个TaskSet,也就是Stage,Stage的划分和调度是由DAGScheduler来负责的,Stage有非最终的Stage(Shuffle Map Stage)和最终Stage(Result Stage)两种,Stage的边界就是发生Shuffle的地方。
9、DAGScheduler:根据Job构建DAG,并提交给Stage给TaskScheduler。其划分Stage的依据是RDD之间的依赖的关系找出开销最小的调度方法,如图:
10、TaskScheduler:将TaskSet交给Worker运行,每个Executor运行什么Task就在此时发生的,TashScheduler维护所有的TaskSet,当Executor向Driver发生心跳时,TaskScheduler会根据资源剩余情况分配相应的Task,另外TaskScheduler还维护着所有的Task的运行标签,重试失败的Task,如图:
ps:在不同运行模式下任务调度器具体为:
(1)、Spark On Standalone模式为:TaskSchedule。
(2)、Yarn Client模式为:YarnClientClusterScheduler。
(3)、Yarn Cluster模式为:YarnClusterScheduler。
总结:
Job=多个stage,Stage=多个同种task, Task分为ShuffleMapTask和ResultTask,Dependency分为ShuffleDependency和NarrowDependency。
三、Spark各体系部分:
1、Driver:
(1)、一个spark作业运行的时候包括一个Driver进程,也就是作业的主进程,具有main函数,并且有SparkContext的实例,是程序得主入口。
(2)、功能:负责向集群申请资源,向master注册信息,负责作业的调度,作业的解析,生成stage并调度Task到Executor上。
(3)、Driver在程序运行之前,已经申请过了资源,Driver和Executor进行通讯,不需要和Master进行通讯。
2、Cluster Manager:
(1)、Master
(2)、Yarn
(3)、Mesos
3、Worker:
(1)、管理当前节点内存,CPU使用情况,接受Master分配过来的资源指令。
(2)、发送心跳的时候,主要给Master发送workId,运行代码的工作是Executor。
(3)、BlockManager:管理Spark中的数据,无论数据在磁盘还是在内存中。
4、BlockManager原理:
(1)、Driver上有BlockManagerMaster,负责各节点上的BlockManger内存管理的元数据进行维护。
(2)、每个BlockManager由四个组件:DiskStore负责对磁盘上的数据进行读写;MemoryStore负责对内存中的数据进行读写;ConnectionManager负责建立BlockManager到远程节点的BlockManager的网络连接;BlockTransferServer负责对远程其他节点的BlockManager的数据读写。
(3)、每个BlockManager创建之后会向BlockManagerMaster进行注册,BlockManagerMaster会为其创建对应的BlockManagerInfo。
(4)、BlockManager进行写操作时,比如RDD运行过程中的中间数据,或则指定的persist,会优先将数据写入内存,内存大小不够才会将部分数据写入磁盘。
(5)、如果persist指定要replication,那么会使用BlockTransferServer将数据的一份副本拷贝到其他的节点上。
(6)、BlockManager进行数据读写的时候,比如shuffleRead操作,如果能从本地读取数据,那么就会利用DiskStore或MemoryStore从本地读取数据,如果本地没有数据,就会用ConnectionManager与有数据的BlockManager建立连接,然后用BlockTransferServer从远程BlockManager读取数据。
(7)、只要使用BlockManager执行了数据增删改查的操作,那么就必须将Block的BlockStatus上报到BlockManagerInfo内部到BlockStauts进行增删改查,从而对元数据进行维护。
四、Spark中的RDD:
1、机制:RDD分布式弹性数据集,简单理解就是一种数据结构,RDD执行过程中会形成DAG图,然后lineage保证容错性。从屋里角度来说,RDD存储的是Block和Node之间的映射。
2、五大特性:
(1)、RDD是由一个或则多个Partition组成的List。每一个Partition都会被一个Task处理,分区数决定了并行计算的数量,默认情况下,HDFS上面一个Block就是一个Partition。
(2)、每一个Partition都有一个计算函数。RDD中的Partition是并行的,所以是分布式计算的。
(3)、依赖于其他的RDD列表。
(4)、key-value数据类型的RDD分区器、控制分区策略和分区数。
(5)、每个分区都有一个优先位置列表。
3、宽窄依赖:
(1)、宽依赖:多个子RDD的Partition依赖一个父RDD的Partition。
(2)、窄依赖:每一个父RDD的一个Partition只被一个子RDD的Partition使用。
4、创建方式:
(1)、并行化创建:一个已经存在于Driver Program中的集合,如set、list。
(2)、读取外部存储上面的数据:比如HDFS、Hive、HBase,或则任何提供Hadoop InputFormat的数据源,也可以本地读取txt、csv数据集。
5、RDD操作函数:
(1)、transformation:返回值是RDD,不会马上提交到Spark集群运行。例如:Map、Filter、groupBy、reduceByKey,
(2)、action:返回值不是RDD,会形成DAG图,提交到Spark集群运行,并立即返回结果。例如collect、foreach。
(3)、注意:reduce是action算子。
(4)、CrontroRoller:crontroroller是控制算子,比如cache、persist。
(5)、cache和persist的区别:cache和persist都是持久化的算子,cache的默认缓存等级只有MEMORY_ONLY,cache底层是调用persist的,persisi可以根据需要设置缓存等级。在checkPoint之前应该做一个cache或则persist操作,将结果保存起来,shuffle之后做persist,因为shuffle会涉及到网络传输,可能会丢失数据,shuffle之前做persist,框架默认将数据持久化到磁盘。
6、数据本地性:
(1)、PROCESS_NODE:缓存在本地节点的数据。
(2)、NODE_LOCAL:本地节点磁盘上的数据。
(3)、ANY:指非本地节点数据。
五、Spark中的容错机制:
1、checkPoint:数据检查点,会发生拷贝,浪费资源。适用于宽依赖。
2、lineAge:记录数据的更新,每次更新都会记录下来,比较复杂且比较耗费性能。适用于DAG中的lineAge太长,重算太耗费时间。
(1)、lazy的记录了数据的来源,RDD是不可变的,且是lazy级别的,且RDD之间构成了链条,lazy是弹性的基石。
(2)、记录元数据,每次修改都记录,写或则修改操作都是基于RDD粗粒度的,RDD的读取可以是细粒度,也可以是粗粒度。
(3)、简化复杂度。
六、Spark中数据倾斜的解决办法:
1、前提是定位数据倾斜,是OOM了,还是任务执行缓慢,可以看日志,看webUI。
2、避免不必要的shuffle。
3、分拆发生数据倾斜的记录。
4、改变并行度,可能并行度太少了,导致个别Task的压力太大了。
5、两阶段聚合,先局部聚合,再全局聚合。
6、自定义partition,分散key的分布,使其更加均匀。
七、Spark中的累加器和广播变量:
1、累加器:
(1)、全局唯一的,只增不减,记录全局集群的唯一状态。
(2)、在Executor中修改它,在Driver中读取它,只能在Driver端定义初始化。
2、广播变量:(1)、只能在Driver端定义,不能再Executor端定义。
(2)、在Driver端可以修改广播变量的值,在Executor中无法修改广播变量的值。
(3)、如果Exectuor端获取到了Driver的变量,如果不使用广播变量Exector有多少个Task就有多少Driver端的变量副本。反之就只有一份。
3、区别:累加器是Executor级别的共享,广播变量是Task级别的共享两个Application,不可以共享累加器,但是同一个Application不同的Job可以共享。
八、Spark中Shuffle:
1、ShuffleManager:主要复制shuffle过程中的执行,计算和处理的组件,Spark1.2之前是HashShuffleManager,Spark1.2之后是SortShuffleManager。Shuffle是划分DAG中Stage的标识,RDD中的Transformation函数中,又分为宽依赖和窄依赖,这两个主要的区别就是是否发生Shuffle,宽依赖会发生Shuffle。
2、HashShuffleManager:
(1)、ShuffleWriter:1、会创建出M*R个文件,文件的开销很大;2、数据的落盘是通过ShuffleWriterGroup的writers方法得到一个DiskBlockObjectWriter对象;3、writers是通过ShufflleWriterDependency来获取后续Partition的数量;4、输出结果放在HashMap中;个人认为的亮点:每一个Partition相当于一个任务,这个数量和后续的任务相对应,从而形成流水线高效并发地处理任务。
(2)、ShuffleRead:1、都是使用HashShuffleReader的read方式;2、调用MapOutputTracer的getMapSizesByExecutorId方法来获取上游Shuffle的位置信息;3、请求Driver端的MapOutputTrackerMaster来获取上游Shuffle的位置信息;4、判断ShuffleDependency是否定义aggeration;5、采用外部排序的方式来对数据进行排序并放入内存中。
3、SortShuffleManager:
(1)、ShuffleWriter:1、判断是否需要Combine,如果需要,则在外部排序中进行聚合并排序;2、外部排序用PartitionedAppendOnlyMap来存放数据;3、Map超过阈值则spill到磁盘,所有数据处理完则merge内存和磁盘的数据,形成一个大文件;4、每个Partition的在数据文件中的起始位置和结束位置写入到索引文件;个人认为的亮点:减少文件的输出,aggregator从内存操纵移动到了磁盘。
(2)、ShuffleRead:1、都是使用HashShuffleReader的read方式;2、调用MapOutputTracer的getMapSizesByExecutorId方法来获取上游Shuffle的位置信息;3、请求Driver端的MapOutputTrackerMaster来获取上游Shuffle的位置信息;4、判断ShuffleDependency是否定义aggeration;5、采用外部排序的方式来对数据进行排序并放入内存中。
九、Spark中的优化:
1、平台层面的调优:防止不必要的jar包分发,提高数据的本地性,选择高效的存储格式如parquet。
2、应用程序层面的调优:过滤操作符的优化降低过多小任务,降低单条记录的资源开销,处理数据倾斜,复用RDD进行缓存,作业并行化执行等等。
3、JVM层面的调优:设置合适的资源量,设置合理的JVM,启用高效的序列化方法如kyro,增大off head内存等等