Deploy模块详解
Spark的Cluster Manager有以下几种部署模式:Standalone、Mesos、YARN、EC2、Local。
Deploy模块是spark standalone的分布式框架,其采用master/slave架构。
5.1Spark运行模式概述
在SparkContext的创建过程中,会通过传入的Master URL的值来确定不同的运行模式,并且创建不同的SchedulerBackend和TaskScheduler。
5.1.1 local
-
Master URL如果使用以下方式,那么就是以本地方式启动Spark
-
1.local
- 使用一个工作线程来运行计算任务,不会重新计算失败的计算任务。
-
2.local[N] / local[*]
- 对于local[N],使用N个工作线程;对于local[*],工作线程的数量取决于本机的CPU Core的数目,保证逻辑上一个工作线程可以使用一个CPU Core。和local一样,不会重新计算失败的计算任务。
-
3.local[ threads, maxFailures ]
- threads设置了工作线程的数目;maxFailures则设置了计算任务最大的失败重试次数。
-
4.local-cluster[ numSlaves, coresPerSlave, memoryPerSlave ]
- 伪分布式模式,本机会运行Master和Worker。其中numSlaves设置了Worker的数目;corePerSlave设置了Worker所能使用的CPU Core的数目;memoryPerSlave设置了每个Worker所能使用的内存数。
-
对于前三种方式,内部实现是相同的,区别就是启动的工作线程数和计算失败时重试的次数不一样。
-
对于第四种伪分布式模式,实际上是在本地机器模拟了一个分布式环境,除了Master和Worker都运行在本机外,与Standalone模式并无区别。
5.1.2 Mesos
- Apache Mesos采用了Master/Slave的架构,主要由四部分组成:Mesos Master、Mesos Slave、Framework(也称为Mesos Application)和Executor。并且Mesos通过Zookeeper实现了Master的高可用性。
- Mesos Master是整个系统的核心。他通过framework_manager管理接入的各个framework,通过slave_manager管理所有的Slave,并将Slave上的资源按照某种分配策略 分配给framework。
- Mesos Slave需要将自己的资源情况汇报给Master(当前主要的资源主要有CPU和Memory两种),负责接受并执行来自Mesos Master的命令,并且为运行在本节点的Task分配资源并且管理这些Task。当前的Mesos也支持很多的容器技术,可以很方便的做到各个计算任务的资源隔离。
- Framework指的是外部的计算框架,这些计算框架通过注册接入Mesos后,由Master进行统一管理和资源分配。要接入的外部框架必须实现一个调度模块,该调度模块负责框架内部的任务调度,即外部框架从Mesos获得了资源后,需要由这个调度模块分配给本框架中的计算任务。
换句话说,Mesos系统采用了双层调度架构:
1)由Mesos将资源分配给外部框架。
2)外部框架的调度模块将资源分配给外部框架的内部计算任务。 - Executor主要用于启动外部框架内部的计算任务。由于不同的框架中启动任务的接口或者方式都不相同,因此Mesos规定外部框架需要实现自己的Executor。这样Mesos就知道如何去启动不同框架下的计算任务。
- Mesos的资源调度可以分成两类,即粗粒度调度和细粒度调度。
- 粗粒度的调度方式是每个Executor获得资源后就长期持有,直到应用程序退出才会释放资源。这种调度方式的优点就是减少了资源调度的时间开销,缺点是由于其分配的资源被长期占有,在应用程序大部分的计算任务都已经完成的情况下,会造成资源的浪费。尤其是有些计算任务出现长尾时,这个资源浪费的情况可能会变得不可接受。
- 细粒度的资源调度是根据任务的实际需要动态申请的,任务完成后就会将资源还给系统,所以避免了粗粒度调度的资源浪费问题。但是由于每次任务的调度都要从系统动态申请资源,调度的时间开销大。特别是对于那些运行时间很短但是计算任务数量又多的应用程序来说,性能会受到较大影响。
- Spark可以通过选项spark.mesos.coarse来设置是采用粗粒度的调度模式还是细粒度的调度模式。
5.1.3 YARN
-
Page83
-
ResourceManager(即资源管理器)全局管理所有应用程序计算资源的分配。他和每一台机器的NodeManager(即节点管理服务器)能够管理应用在那台机器上的进程并能对计算进行组织。
-
每一个应用的ApplicationMaster则负责相应的调度和协调。ApplicationMaster是一个详细的框架库,他结合从ResourceManager获得的资源和NodeManager协同工作来运行和监控任务。
每一个应用的ApplicationMaster的职责有:向调度器索要适当的资源容器,运行任务,跟踪应用程序的状态和监控它们的进程,处理任务的失败原因。 -
ResourceManager支持分层级的应用队列,这些队列享有集群一定比例的资源。从某种意义上讲他就是一个纯粹的调度器,它在执行过程中不对应用进行监控和状态跟踪。同样,他也不能重启因应用失败或者硬件错误而运行失败的任务。
-
ResourceManager是基于应用程序对资源的需求进行调度的;每一个应用程序需要不同类型的资源因此就需要不同的容器。资源包括:内存、CPU、磁盘、网络等。可以看出,这同现MapReduce固定类型的资源使用模型有显著区别,他给集群的使用带来负面的影响。资源管理器提供一个调度策略的插件,他负责将集群资源分配给多个队列和应用程序。调度插件可以基于现有的能力调度和公平调度模型。
-
NodeManager是每一台机器框架的代理,是执行应用程序的容器,监控应用程序的资源使用情况(CPU、内存、硬盘、网络)并且向调度器汇报。
-
在Client提交了Job后,Application Master会向ResourceManager请求资源,在获得了资源后,Application Master会在NodeManager上启动Container,运行计算任务,并且和Container保持联系,监控任务的运行状态等。
-
1.YARN Cluster模式
- YARN Cluster模式,就是通过Hadoop YARN来调度Spark Application所需要的资源。
- 用户提交的Application会通过YARN Client提交到YARN的主节点ResourceManager上,ResourceManager会在一个工作节点上启动ApplicationMaster(实现是org.apache.spark.deploy.yarn.ApplicationMaster)。启动了ApplicationMaster后,才算是完成了Spark Application的提交。
- ApplicationMaster在将自己注册成为一个YARN ApplicationMaster后,才会开始执行用户提交的Application。
-
2.YARN Client模式
- 该模式和YARN Cluster模式的区别在于,用户提交的Application的SparkContext是在本机上运行,适合Application本身需要在本地进行交互的场景;而YARN Cluster中,所有的计算都是在YARN的节点上运行的。
5.2模块整体架构
Deploy模块采用的也是典型的Master/Slave架构,其中Master负责整个集群的资源调度和Application管理。Slave(即Worker)接收Master的资源分配调度命令后启动Executor,由Executor完成最终的计算任务。而Client则负责Application的创建和向Master注册Application,并且负责接收来自Executor的状态更新和计算结果等。
Deploy模块主要包含3个子模块:Master、Worker、Client,他们之间的通信通过AKKA完成。对于Master和Worker,他们本身就是一个Actor,因此可以直接通过AKKA实现通信。Client本身不是一个Actor。
这三者的主要职责如下:
1)Master:接收Worker的注册并管理所有的Worker,接收Client提交的Application,FIFO调度等待的Application并向Worker提交。
2)Worker:向Master注册自己,根据Master发送的Application配置进程环境,并启动StandaloneExecutorBackend。
3)Client:向Master注册并监控Application。当用户创建SparkContext的时候会实例化SparkDeploySchedulerBackend,而实例化SparkDeploySchedulerBackend的同时会启动Client,通过向Client传递启动参数和Application有关信息,Client向Master发送请求注册Application并且在计算节点上启动StandaloneExecutorBackend。
5.3消息传递机制详解
5.3.1 Master和Worker
-
Master作为整个集群的管理者,需要Worker通过注册、汇报状态来维护整个集群的运行状态,并且通过这些状态来决定资源调度策略等。
-
Worker向Master发送的消息主要包含三类
- 1)注册:Worker启动时需要向Master注册,注册时需要汇报自身的信息。
- 2)状态汇报:汇报Executor和Driver的运行状态;在Master故障恢复时,需要汇报Worker上当前运行的Executor和Driver的信息。
- 3)报活心跳:Worker每隔指定周期会向Master发送报活的心跳。
-
Master向Worker发送的消息除了相应Worker的注册外,还有一些控制命令,包括让Worker重新注册、让Worker启动Executor或者Driver、停止Executor和Driver等。
5.3.2 Master和Client
-
这里的Client分为Driver Client和App Client。
-
Driver Client作用:
- 1)向Master提交Driver
- 2)向Master发送KillDriver的请求
- 3)获取Driver的当前运行状态
-
AppClient的作用:
- 1)AppClient向Master注册Application
- 2)Master在故障恢复后,会通过发送消息通知AppClient和Worker。AppClient接到后会更改保存的Master信息并回复。
-
Master向Client发送:
- 1)注册是否成功
- 2)Master收到Driver Client的Kill请求之后,会判断Driver是否还在运行,如果在等待调度的阶段,那么直接从等待列表删除;如果已经在运行状态,那么通过消息通知Worker停止该Driver
- 3)回复Driver查询当前运行状态的请求
5.3.3 Client和Executor
-
Driver向Executor发送的消息分为两类:
- 1)启动Task,停止Task
- 2)相应Executor注册的请求,回复成功还是失败
-
Executor向Driver发送的消息:
- 1)注册Executor
- 2)汇报Executor中运行的Task的状态
5.4集群的启动
5.4.1 Master的启动
-
Master是一个Actor,因此Worker和AppClient可以直接和他通过AKKA进行通信。一个集群可以部署多个Master,以达到高可用性的目的。
-
Spark的Standalone模式支持一下几种方式的元数据持久化方法和选举机制:
-
1.ZooKeeper
- 实现了基于ZooKeeper的选举机制,元数据信息会持久化道Zookeeper中。因此在Master故障后,ZooKeeper会在备份的Master中选举出新的Master,新的Master在启动后汇总ZooKeeper中获取原数据信息并且恢复这些数据。
-
2.FILESYSTEM
- 集群的元数据信息会保存在本地文件系统。而Master启动后则会立即成为Active的Master。如果不考虑机器本身的故障和在设置了Master进程退出后能自动重启的前提下,这种方式也是可以接受的。
-
3.CUSTOM
- 用户自定义的
-
4.NONE
- 不会持久化集群的原数据,Master在启动后会立即接管集群的管理工作。
-
-
如果不设置spark.deploy.recoveryMode,那么默认是NONE,即没有备份的Master,集群所有历史的元数据信息在Master重启后都会丢失。
-
在Master进行启动后,ZooKeeper方式的选举机制会根据自身的策略来选举出Leader;对于FILESYSTEM和NONE,进程启动后会立即成为Leader。
-
被选举为Leader的Master,会首先读取集群的元数据信息,如果有读到的数据,那么Master的状态就会变为RecoveryState.RECOVERING,然后开始恢复数据和通知Worker、AppClient和Driver Client,Master已经更改,恢复结束后Master 的状态会变为RecoveryState.ALIVE。
对于没有读取到任何数据的Master,状态会立即变为RecoveryState.ALIVE。
Master只有在状态是RecoveryState.ALIVE时才对外服务,包括接收Worker、Application和Driver Client 的注册和状态更新等。
5.4.2 Worker的启动
- Worker的启动相对于Master的启动要简单,Worker只会做一件事,就是向Master注册。
注册成功后,Worker就可以对外服务了,即可以接受Master的指令等。
5.5集群容错处理
容错(fault tolerance)指的是在一个系统的部分模块出现错误的情况下还能持续的对外提供服务;如果出现了服务质量的下降,这个下降也是和出错的严重性成正比的。对于没有容错的系统,即时一个微小的错误也可能导致整个服务停止。
提到容错,不得不提一下容灾(或者称为灾难恢复,disaster recovery)。容灾技术是通过在异地建立和维护一个备份系统,利用地理上的分散性来保证数据对于灾难性事件的抵抗能力。容灾系统在实现上可以分为两个层次:数据容灾和应用容灾。数据容灾指建立一个异地的数据系统,作为本地关键应用数据的一个备份。应用容灾是在数据容灾的基础上,在异地建立一套完整的和本地生产系统相同的备份应用系统(可以是互为备份)。灾难情况下,由远程系统迅速接管业务运行。
容错和容灾都是为了实现系统的高可用性,容错是在系统的部分模块出现问题时的错误恢复机制;容灾是在整个系统的层面,通过使用数据和应用的镜像,来实现服务的高可用性的。
5.5.1 Master异常退出
- 如果Master异常退出,此时新的计算任务就无法进行提交了。虽然老的计算任务可以继续运行,但是由于状态更新等都中断了,很多功能也同时受到影响。比如计算资源任务完成后的资源回收,这个回收指令是Master发送给Worker。因此,Master的异常退出,是一个非常严重的错误。
- 前面提到过集群可以部署多个Master,借助ZooKeeper的Leader选举机制选出一个Master作为集群的管理者,其他的都作为备份。因此,在这种情况下Master 的异常退出,ZooKeeper会在备份的Master中选择一个充当集群的管理者。
这个被新选出来的Master会首先从ZooKeeper中读取集群的元数据(包括Worker、Driver Client和Application的信息)进行数据恢复,然后告知Worker和AppClient,Master已经更换的消息。在收到所有的Worker和AppClient的相应或者超时后,Master就会变成ACTIVE的状态,并开始对外提供服务 。
因此,对于生产环境的系统,推荐使用这种方式。
5.5.2 Worker异常退出
- 对于一个集群来说,Worker的异常退出的概率非常高。Worker退出时,集群是如何进行容错处理的呢?
- 1)Worker在退出前,会将所有运行在它上面的Executor和Driver Client删除。
- 2)Worker需要周期性的向Master发送心跳消息。这个周期就是spark.worker.timeout(默认60s)设置的1/4。
由于Worker 的异常退出,使得他的心跳会超时,Master认为该Worker已经异常退出,那么Master会将Worker上运行的所有Executor的状态标记为丢失(ExecutorState.LOST),然后将这个状态更新通过消息通知AppClient;对于该Worker上运行的Driver Client,如果他设置了需要重启(即设置了supervise),那么需要重新调度来重新启动这个Driver Client,否则直接将他删除,并且将状态设置为DriverState.ERROR。 - 3)AppClient接到Master 的StatusUpdate消息后会将状态更新汇报到org.spache.spark.scheduler.cluster.SparkDeploySchedulerBackend,而它会根据消息内容判断是否是Executor异常退出。
然后重新进行调度,Task会被分配新的Executor,完成最终的计算。
5.5.3 Executor异常退出
- Executor模块负责运行Task计算任务,并将计算结果会传到Driver。
由于Executor的异常退出,Master将会为该Application分配新的Executor。如果失败次数超过10次,那么就会将这个Application标记为失败。
5.6Master HA实现详解
使用ZooKeeper实现HA(High Availability)高可用性。众所周知,ZooKeeper提供了一个Leader选举机制,利用这个机制可以保证虽然集群存在多个Master但是只有一个是Active的。当Active的Master出现故障时,另外一个Standby Master会被选举出来。
由于集群的信息,包括Worker、Driver Client和Application的信息都已经持久化到ZooKeeper中,因此在切换的过程中只会影响新Job的提交,对于正在进行的Job没有任何的影响。
5.6.1 Master启动的选举和数据恢复策略
- 除了集群搭建后的第一次启动,Master每次启动都会恢复集群当前的运行状态,这些状态包括当前正在运行的Application、Driver Client和Worker。当前的Standalone支持ZooKeeper、FILESYSTEM、CUSTOM、NONE四种策略。
将所有的策略抽象为持久化和选举两部分,从而实现了一个Pluggable(可插拔、可扩展的)框架,因此第三方可以很容易地实现自定义的策略。
Spark使用的并不是ZooKeeper原生的API,而是Apache Curator,Curator在ZooKeeper上做了一层有好的封装。
5.6.2 集群启动参数的配置
5.6.3 Curator Framework简介
- Curator Framework极大地简化了ZooKeeper的使用,他提供了high-level的API,并且基于ZooKeeper添加了很多特性,包括:
- 1)自动连接管理:连接到ZooKeeper的Client可能会连接中断,Curator处理了这种情况,对于Client来说自动重连是透明的。
- 2)简洁的API:简化了原生态的ZooKeeper的方法,事件等;提供了一个简单易用的接口。
- 3)Recipe的实现