Spark集群搭建与运行流程

Spark集群搭建与运行流程

服务器准备

我使用的是ubuntu-16.04版本的4个虚拟主机,主机名为s200,s201,s202,s203
spark安装包spark-2.1.0-bin-hadoop2.7.tgz,在这里我使用了root用户进行集群的搭建
集群规划
s200 : 用作Master
s201-s203:用作Worker

服务器的ssh配置

1)ssh-keygen -t rsa 生成公钥和私钥
2)将id_rsa.pub分发至远程服务器上,并在远程服务器将分发得到的公钥cat id_rsa.pub >> ~/.ssh/authorized_keys中就可免密码登陆
3)ssh下的各目录说明
known_hosts:ssh会把每个你访问过计算的公钥(public key)都记录在此文件中,当下次访问相同计算机时,OpenSSH会核对公钥,如果公钥不同,OpenSSH会发出警告, 避免你受到DNS Hijack之类的攻击
authorized_keys:就是为了让两个linux机器之间使用ssh不需要用户名和密码。采用了数字签名RSA或者DSA来完成这个操作

spark集群搭建

1)修改spark-env.sh配置文件

# 把SPARK_HOME/conf/下的spark-env.sh.template文件复制为spark-env.sh
# 修改spark-env.sh配置文件,添加一些配置信息
# vim spark-env.sh
# 配置JAVA_HOME,一般来说,不配置也可以,但是可能会出现问题,还是配上吧
export JAVA_HOME=/usr/local/java/jdk1.8.0_73
# 一般来说,spark任务有很大可能性需要去HDFS上读取文件,所以配置上
# 如果说你的spark就读取本地文件,也不需要yarn管理,不用配
export HADOOP_CONF_DIR=/home/hadoop/apps/hadoop-2.7.4/etc/hadoop

# 设置Master的主机名
export SPARK_MASTER_HOST=hadoop01
# 提交Application的端口,默认就是这个,万一要改呢,改这里
# 为什么默认就是7077呢?我们在sbin/ vim start-master.sh可以看到
# if [ "$SPARK_MASTER_PORT" = "" ]; then
#   SPARK_MASTER_PORT=7077
# fi
# 但是我们最好在这里统一配置
export SPARK_MASTER_PORT=7077
# 每一个Worker最多可以使用的cpu core的个数,我虚拟机就一个...
# 真实服务器如果有32个,你可以设置为32个
export SPARK_WORKER_CORES=1
# 每一个Worker最多可以使用的内存,我的虚拟机就2g
# 真实服务器如果有128G,你可以设置为100G
export SPARK_WORKER_MEMORY=1g

2)修改slaves配置文件,添加Worker的主机列表

# 把SPARK_HOME/conf/下的slaves.sh.template文件复制为slaves.sh
s201
s202
s203

3)把spark_home/sbin下的start-all.sh和stop-all.sh这个文件重命名
这一步可做可不做。
如果集群中也配置HADOOP_HOME,那么在HADOOP_HOME/sbin目录下也有start-all.sh和stop-all.sh这两个文件,当你执行这两个文件,系统不知道是操作hadoop集群还是spark集群。修改后就不会冲突了,当然,不修改的话,你需要进入它们的sbin目录下执行这些文件,这肯定就不会发生冲突了。我们配置SPARK_HOME主要也是为了执行其他spark命令方便。
4)把spark安装包分发给其他节点

scp -r spark-2.1.0 s201:`pwd`
scp -r spark-2.1.0 s202:`pwd`
scp -r spark-2.1.0 s203:`pwd`

5)在集群所有节点上配置SPARK_HOME环境变量

vim /etc/profile
export SPARK_HOME=/application/spark2.1.0
export PATH=$SPARK_HOME/bin:$SPARK_HOME/sbin:$PATH
source /etc/profile

6)在spark master节点启动saprk集群

# 注意,如果你没有执行第4步,一定要进入SPARK_HOME/sbin目录下执行这个命令
# 或者你在Master节点分别执行start-master.sh和start-slaves.sh
start-spark-all.sh
# 注意,如果配置了HADOOP_CONF_DIR,那么在启动spark集群之前,先启动hadoop集群

7)验证

root@s200:~# jps
3729 Master
4050 Jps
root@s200:~# 
root@s201:~# jps
14805 Jps
8678 Worker
root@s201:~# 
root@s202:~# jps
12307 Jps
7397 Worker
root@s202:~# 
root@s203:~# jps
2363 Worker
2462 Jps
root@s203:~# 

在这里插入图片描述

术语解释

Master :资源管理的主节点(进程)
Cluster Manager :在集群上获取资源的外部服务(例如standalone,Mesos,Yarn)
Worker Node(standalone):资源管理的从节点(进程)或者说管理本机资源的进程
Application:基于Spark的用户程序,包含了driver程序和运行在集群上的executor程序
Driver Program:用于来连接工作进程(Worker)的程序
Executor:是在一个worker进程所管理的节点上为某Application启动的一个进程,该进程负责运行任务,
并且负责将数据存在内存或者磁盘上,每个应用都有各自独立的executors
Task:被送到某个executor上的工作单元
Job:包含很多任务(Task)的并行计算,可以看作和action对应
Stage:一个Job会被拆分成很多组任务,每组任务被称为Stage(就像Mapreduce分map task和reduce task一样)

spark资源调度

集群启动后,Worker节点会像Master节点汇报资源情况,Master掌握了集群资源情况。当Spark提交一个Application后,根据RDD之间的依赖关系将Application形成一个DAG有向无环图。任务提交后,Spark会在Driver端创建两个对象:DAGScheduler和TaskScheduler,DAGScheduler是任务调度的高层调度器,是一个对象。DAGScheduler的主要作用就是将DAG根据RDD之间的宽窄依赖关系划分为一个个的Stage,然后将这些Stage以TaskSet的形式提交给TaskScheduler(TaskScheduler是任务调度的低层调度器,这里TaskSet其实就是一个集合,里面封装的就是一个个的task任务,也就是stage中的并行度task任务),TaskSchedule会遍历TaskSet集合,拿到每个task后会将task发送到计算节点Executor中去执行(其实就是发送到Executor中的线程池ThreadPool去执行)。task在Executor线程池中的运行情况会向TaskScheduler反馈,当task执行失败时,则由TaskScheduler负责重试,将task重新发送给Executor去执行,默认重试3次。如果重试3次依然失败,那么这个task所在的stage就失败了。stage失败了则由DAGScheduler来负责重试,重新发送TaskSet到TaskSchdeuler,Stage默认重试4次。如果重试4次以后依然失败,那么这个job就失败了。job失败了,Application就失败了。
TaskScheduler不仅能重试失败的task,还会重试straggling(落后,缓慢)task(也就是执行速度比其他task慢太多的task)。如果有运行缓慢的task那么TaskScheduler会启动一个新的task来与这个运行缓慢的task执行相同的处理逻辑。两个task哪个先执行完,就以哪个task的执行结果为准。这就是Spark的推测执行机制。在Spark中推测执行默认是关闭的。推测执行可以通过spark.speculation属性来配置。
在这里插入图片描述
1)待集群spark启动成功后,worker与master通信,此时worker的各种信息(IP,port等)会存在Master中的workers集合中,其数据类型是HashSet。
2)当spark submit向Master为Driver申请资源时,申请信息会封装在Master中的waitingDrivers集合中,此时有个Schedule() 方法会监控waitingDrivers集合是否为空,若不为空,说明客户端向Master申请资源,然后查看当前集群的资源情况,从而找到符合要求的节点启动Driver,待Driver启动成功,就把这个申请信息从waitingDrivers集合中删除。
3)Driver启动成功后,Driver会像Master为Application申请资源,申请信息会封装在Master中的waitingApps集合中,同样Schedule()方法会监控waitingApps集合是否为空,若不为空,说明有Driver为当前Application申请资源,然后查看当前集群的资源情况,从而找到符合要求的节点去启动Executor进程,待Executor启动成功后,就把这个申请信息从waitingApps集合中删除。
总结:
当为Driver或者当前Application申请资源时,会直接调用Schedule()方法,根据不同的申请去反调相应的方法,即一个Schedule()方法中有两套处理逻辑
资源调度结论:
1、默认情况下,每一个Worker会为当前的Application启动一个Executor进程,并且这个Executor会使用1G内存和当前Worker所能管理的所有core
2、如果想要在一个Worker上启动多个Executor,可以在提交Application的时候,指定Executor使用的core数,命令为:spark -submit --executor-cores。
3、默认情况下Executor的启动方式为轮训启动。
Executor在worker上启动的条件是什么?
1、Worker分配给Executor的cores大于Executor所需要的最小cores。
2、Worker空闲 cores大于Executor所需最小cores。
3、Worker的空闲内存大于Executor所需要的内存。

spark任务调度

Spark是一个分布式并行计算框架。我们写的Application要在集群中分布式计算,由于大数据中的计算原则是计算数据,为了将每一个task精准的分发到节点上,此时需要任务调度器,找到数据的位置,从而分发task到节点上。
在这里插入图片描述
任务调度过程:
首先根据RDD的依赖关系生成DAG有向无环图,然后将有向无环图交给DAGScheduler;
1)根据RDD的宽窄依赖关系,将DAG切割成一个个的stage,将切割出来的stage封装到TaskSet对象,然后将一个个的TaskSet给TaskScheduler
2)TaskScheduler拿到TaskSet以后,会遍历这个结果,拿到每一个task,然后去调用HDFS上的某一个方法,获取数据的位置,根据数据的位置来分发task到worker节点的Executor进程中的线程池中执行
3)TaskScheduler会实时跟踪每一个task的执行情况,若执行失败,TaskScheduler会重试提交task,不会无休止的重试,默认是重试3次,如果重试3次依旧失败,那么这个task所在stage就失败了,此时TS向DAGScheduler汇报
4)TaskScheduler向DAGScheduler汇报当前stage失败,此时DAGScheduler会重试提交stage。注意:每一次重试提交的stage,已经成功执行的不会被再次分发到Executor进程执行,只是提交重试失败的。如果DAGScheduler重试了4次依然失败,那么stage所在的job就失败了,job失败是不会进行重试的。DAGScheduler重试次数spark.stage.maxConsecutiveAttempts可设置。

资源调度与任务调度整合

在这里插入图片描述
整个过程中的部分问题
1、客户端没有向Master为Driver申请资源,Driver是如何启动起来的?
通过Application程序中SparkContext上下文启动起来的
2、为什么waitingWorker的数据类型是HashSet?
这里主要是用到了Set的唯一性,当worker与Master失去通信的时候,Master会设置一个时间间隔,若超过时间间隔worker还没有与Master建立通信,那么Master会认为这个worker挂掉了,从而释放这部分资源,若建立通信,Master则把原来那部分资源分配给worker,从而保证每个worker分配到一份资源
3、启动Executor的饭是钢hi为轮询启动,其优点是什么?
这种启动方式可以使计算能够更好地找到数据,有助于数据的本地化。

粗细粒度资源调度

粗粒度资源申请(spark)

当application执行之前,会将所有的资源申请完毕,申请到资源,就执行application,申请不到一直等待。当所有的task执行完毕之后才会释放这批资源
优点:application执行之前资源申请完毕,每个task执行时就不需要自己去申请资源,task执行就快了, task快了,job就快了,application执行就快了
缺点:所有的task执行完毕之后才会释放资源,容器使集群资源不能充分利用(如有数据倾斜的时候,99个task都执行完了,就剩一个task一直在执行)

细粒度资源申请(Map Reduce)

当application执行时,由执行任务的task自己去申请资源
优点:资源得到充分利用
缺点:效率不高

posted @ 2019-03-09 10:52  刘丽刚  阅读(4141)  评论(0)    收藏  举报