在此文章《基于Centos7.5完整部署分布式Hadoop3.1.2》里,已经给出详细的hadoop和yarn的部署过程,既然已经解决了大数据开发中“hdfs”的数据存储部署,那么就要考虑如何基于底层分布式文件基础上运行计算框架,以便进行更高层次的应用开发。在本篇文章中,将给出完整部署spark计算框架集群。
1、spark版本(仅列出spark相关)
spark-2.4.4-bin-hadoop2.7,该版本的spark支持hadoop2.7以及之后的版本
scala-2.13.1:使用Scala语言开发数据处理逻辑,当然也可使用python进行spark数据处理逻辑开发,官网有给出pyspark相关指导教程。
三台节点都需要配置,目录放置路径:
1 | [root@nn opt]# ls |
spark HA集群规划,这里只列出spark HA集群的有关进程,hadoop的进程不再列出
IP,hostname | spark集群中负责的角色 | Spark 路径 | Scala路径 | 物理内存 |
---|---|---|---|---|
192.188.0.4,nn | master,worker,spark-history-server | /opt/spark-2.4.4-bin-hadoop2.7 | /opt/scala-2.13.1 | 2G |
192.188.0.5,dn1 | master,worker | /opt/spark-2.4.4-bin-hadoop2.7 | /opt/scala-2.13.1 | 1G |
192.188.0.6,dn2 | master,worker | /opt/spark-2.4.4-bin-hadoop2.7 | /opt/scala-2.13.1 | 1G |
这里spark master节点nn的物理内存给了2G,因为该节点不仅仅启动了spark相关主服务,还得启动hadoop相关主服务,如果物理内存不足,在后面章节中启动spark-shell或者跑application都无法正常启动,提示资源不足。
2、设置path环境
三个节点都需要设置
1 | [root@nn opt]# vi /etc/profile |
3、配置spark集群的相关文件
1 | 拷贝一份spark-env.sh文件用于配置spark环境 |
只需在spark-env.sh文件头部加入以下环境变量
1 | export SCALA_HOME=/opt/scala-2.12.8 |
修改conf目录下的slaves文件
1 | [root@dn1 conf]# pwd |
为减少spark主节点nn的内存资源消耗,这里不再将nn设为Worker角色
将修改过的两个文件拷贝到其他两个节点
1 | [root@dn1 spark-2.4.4-bin-hadoop2.7]# scp -r conf/ dn1:/opt/spark-2.4.4-bin-hadoop2.7/ |
4、启动spark集群进程
4.1 启动spark-master进程
spark的进程启动是有步骤的,需先启动master服务,再启动worker进程,因为worker启动需要通过spark://nn:7077 spark协议的7077端口与master节点通信,否则master节点和worker之间无法形成集群。
1 | [root@nn sbin]# ./start-master.sh |
以上表示主节点已经启动Master进程,其他节点dn1和dn2还未启动Worker进程。可以通过log日志文件内容看到其启动过程,这里不再给出,当然更直观的方式是在web端查看:页面http://nn:8080/
或者http://192.188.0.4:8080
可以直观看到master状态,此时workers还未启动,可以按到显示workers数量为0
4.2 在spark master启动后,启动Worker节点
在spark主节点上nn,启动workers,这些workers的对应的节点就是路径/opt/spark-2.4.4-bin-hadoop2.7/conf
下slaves文件配置到2个节点:dn1,dn2。
- 启动spark集群上所有的workers节点命令:start-slaves.sh
启动本节点上的work进程:start-slave.sh
可以对比其shell脚本的差别,在start-slaves.sh脚本后面可以看到
1 | "${SPARK_HOME}/sbin/start-slave.sh" "spark://$SPARK_MASTER_HOST:$SPARK_MASTER_PORT" |
start-slaves.sh其实是在其他节点运行./start-slave.sh spark://nn:7077
实现批量启动其他work节点
1 | [root@nn sbin]# pwd |
在spark的master web端:http://nn:8080
或者http://192.188.0.4:8080
可以看到2个worker均active
每个worker的最大可用内存512m,vCPU 1颗
5、设置启动spark-shell的默认环境(非常关键的配置)
5.1 配置spark-defaults.conf
注意,在启动spark-shell之前,如果需要对/opt/spark-2.4.4-bin-hadoop2.7/conf目录下的配置文件:spark-defaults.conf.template
相关参数进行修改,例如需要结合spark-history-server的配置,那么除了新建一份spark-defaults.conf
,还需要对里面参数正确,否则启动spark-shell会提示出错并退出
因为本文测试使用2G内存,所以需要对配置文件里面做修改,修改如下
1 | [root@nn conf]# cp spark-defaults.conf.template spark-defaults.conf |
如果以上入口地址设错,或者未在namenode节点的hdfs文件系统上创建directory目录,都会导致无法启动spark-shell
==若不对spark-defaults.conf.template参数修改,例如不需要启动history服务,则无需创建spark-defaults.conf文件,也无需进行上述设置,可以直接启动spark-shell==
5.2 spark-defaults.conf的详细的设置
参考官网配置指引
其实该配置就是用来spark集群调优的关键配置
主要分为几大部分的参数配置:
- Application Properties
- Runtime Environment
- Spark UI
- Compression and Serialization
- Memory Management
- Execution Behavior
- Networking
- Scheduling
- Dynamic Allocation
5.3 启动spark-shell
首次启动spark-shell时,会出现‘WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform’的提示,参考文章提示:centos预装的glibc库是2.17版本,而hadoop期望是2.14版本,可以忽略该警告,在hadoop日志配置文件设置:
1 | [root@dn2 ~]# vi /opt/hadoop-3.1.2/etc/hadoop/log4j.properties |
1 | # 启动成功提示 |
可以在http://nn:4040
查看,若有计算任务提交,可以直观查看spark job 、excutors等进度,参考官方说明:
Every SparkContext launches a web UI, by default on port 4040, that displays useful information about the application. This includes:
- A list of scheduler stages and tasks
- A summary of RDD sizes and memory usage
- Environmental information.
- Information about the running executors
但以上启动是有问题的,表面上看,spark-shell已正常启动,但测试机器最大内存为2G,启动spark-shell若不限定executor-memory内存使用(默认值1G)那么在执行计算任务时,spark-shell会一直提示 scheduler资源不足:
WARN scheduler.TaskSchedulerImpl: Initial job has not accepted any resources; check your cluster UI to ensure that workers are registered and have sufficient memory
导致job一直waiting状态
解决办法:
启动spark-shell限制相关资源的使用:
spark-shell --executor-memory 512m --total-executor-cores 3 --executor-cores 1
6、在spark-shell交互式计算words
6.1 存放words的文件已经上传到hdfs文件系统上的/app目录下
1 | [root@nn sbin]# hdfs dfs -ls /app |
6.2带参数启动spark-shell
1 | [root@dn1 ~]# spark-shell --master spark://nn:7077 --executor-memory 512m --total-executor-cores 3 --executor-cores 1 --num-executors 2 |
或者在此spark-shell上交互式使用Scala写简单的统计语句
1 | scala> val file=sc.textFile("hdfs://nn:9000/app") |
7、使用spark的相关web服务页面查看application执行计算作业的详细过程(非常重要)
下面以一个Application 执行job前和执行job后的页面来说明application,job,task等内容
==Application 执行job前==
A、查看application执行的详情页面
在nn节点上,启动一个名字为word-count的application:
1 | [root@nn sbin]# spark-shell --executor-memory 512m --total-executor-cores 3 --executor-cores 1 --num-executors 2 --name word-count |
在spark-shell启动后,会提示:
Spark context Web UI available at http://nn:4040
Spark context available as ‘sc’ (master = spark://nn:7077, app id = app-2019***-0002).
http://nn:4040
针对当前运行application的job详情,如果执行统计命令后退出spark-shell,那么web服务退出,http://nn:4040
将无法访问,也即无法查看当前application执行过程的情况,所有需要配置application 的spark-history-server,用来查看之前已经完成或者未完成的application情况的历史记录http://nn:4040
页面:
app id = app-2019*-0002Jobs栏目内容:
可以看到目前该application没有job需要执行
app id = app-2019*-0002的executor内容:
该application分配了两个executor,分别为dn1节点和dn2节点,nn节点则作为driver
B、查看所有正在完成、已完成的application管理页面:spark master:http://nn:8080
该页面可以看到spark集群的资源分配情况、worker情况、正在runing的application以及已经完成的application
C、在A部分提到如果要回看已经完成application运行情况,则需要启动spark-history-server,这里给出配置文件说明
==配置Spark History Server服务==
history只需在spark主节点上配置,无需在其他两个节点上配置。
spark-history-server其实就是一个web服务,spark.eventLog.dir存放所有application事件日志,web服务通过把这些application运行日志内容以web UI提供查看
1 | [root@nn conf]# vi spark-env.sh |
web访问端口为9001,保留最近5个application的日志,application的日志存放在hdfs://nn:9000/directory
其他配置项
其他相关参数:
Property Name | Default | Meaning |
---|---|---|
spark.history.fs.update.interval | 10s | 文件系统历史提供程序在日志目录中检查新日志或更新日志的周期。较短的间隔可以更快地检测新应用程序,但代价是需要更多的服务器负载重新读取更新的应用程序。一旦更新完成,已完成和未完成的应用程序的清单将反映更改 |
spark.history.retainedApplications | 50 | 在缓存中保留UI数据的应用程序数量。如果超过这个上限,那么最老的应用程序将从缓存中删除。如果应用程序不在缓存中,则必须从磁盘加载它(如果是从UI访问它) |
spark.history.fs.cleaner.enabled | false | 是否周期性的删除storage中的event log(生产必定是true) |
spark.history.fs.cleaner.interval | 1d | 多久删除一次 |
spark.history.fs.cleaner.maxAge | 7d | 每次删除多久的event log,配合上一个参数就是每天删除前七天的数据 |
spark-history页面截图:
==Application 执行job后==
当application开始runing后,可以看到相关job运行情况
A、application的jobs图示
该word-count app启动了两个job
job-0主要负责作业中Transformation链操作:sc.textFile("hdfs://nn:9000/app").flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).sortBy(_._2,false)
job-0分解
job-1负责作业最后阶段Action操作:.collect
application、job、stage、task构成关系
这里job-1的stage2是skip的,因为job-0已经完成了同样的操作,其他job无法重复执行。
B、job-0、job-1对于的stage图
job-0:stage-0和stage-1
job-1:stage-2、stage-3、stage-4
C、以job-0为例:stage-0和stage-1的具体任务执行图DAG调度过程
==job-0:stage-0,其实就是map阶段,对应shuffle write==
==job-1:stage-1,其实就是reduce阶段,对应shuffle read==
8、启动spark HA集群
前面的测试都是基于一个master带2个slave节点的集群,若nn节点上的master进程挂了,显然无法达到高可用集群,因此本章节也给出其配置过程,后面多篇文章会有大数据实时项目相关组件的部署,全部组件都基于HA方式运行,近可能贴近生产环境。
spark HA集群基于zookeeper集群实现,因此需要环境配置好并启动zookeeper服务,这里不再累赘,可以参考本人blog中有关zk集群的配置过程。
8.1 配置文件
spark HA配置相对简单,改动三个文件: spark-defaults.conf,slaves,spark-env.sh
将三个节点spark-defaults.conf都做以下配置:1
2
3
4
5
6
7
8
9
10
11
12[root@nn conf]# pwd
/opt/spark-2.4.4-bin-hadoop2.7/conf
[root@nn conf] vi spark-defaults.conf
# 因为spark要配成HA模式,因此不再指定nn节点为active节点
#spark.master spark://nn:7077
spark.eventLog.enabled true
# 注意这里eventLog.dir,因为本文中hadoop 集群还不是HA模式,NameNode主节点仅有nn节点,因此设为nn:9000。若hadoop集群为HA模式,这里的路径需要设为 :hdfs://hdapp/directory。在后面的spark on yarn 文章也还会提到这一点。
spark.eventLog.dir hdfs://nn:9000/directory
spark.serializer org.apache.spark.serializer.KryoSerializer
spark.driver.memory 512m
spark.driver.cores 1
spark.executor.extraJavaOptions -XX:+PrintGCDetails -Dkey=value -Dnumbers="one two three"
将3个节点都为加入到slaves文件,每个节点都需配置该slaves文件。1
2
3
4
5
6
7[root@dn1 conf]# pwd
/opt/spark-2.4.4-bin-hadoop2.7/conf
[root@dn1 conf]# cp slaves.template slaves
[root@dn1 conf]# vi slaves
nn
dn1
dn2
更改spark-env.sh1
2
3
4
5
6
7
8
9
10export SCALA_HOME=/opt/scala-2.12.8
export JAVA_HOME=/opt/jdk1.8.0_161
# spark HA配置里,不再指定某个节点为master
#export SPARK_MASTER_IP=182.10.0.4
export SPARK_WORKER_MEMORY=512m
# 加入zookeeper集群,由zk统一管理
export SPARK_DAEMON_JAVA_OPTS="-Dspark.deploy.recoveryMode=ZOOKEEPER
-Dspark.deploy.zookeeper.url=nn:2181,dn1:2181,dn2:2181 -Dspark.deploy.zookeeper.dir=/spark"
#hadoop的配置文件**site.xml所在目录
export HADOOP_CONF_DIR=/opt/hadoop-3.1.2/etc/hadoop
在三个节点上都需按以上内容做相同配置。
8.2 启动和测试spark HA
首先启动nn节点上slaves进程,此时三个节点都是worker角色1
2
3
4[root@nn spark-2.4.4-bin-hadoop2.7]# ./sbin/start-slaves.sh
nn: starting org.apache.spark.deploy.worker.Worker, logging to /opt/spark-2.4.4-bin-hadoop2.7/logs/spark-root-org.apache.spark.deploy.worker.Worker-1-nn.out
dn1: starting org.apache.spark.deploy.worker.Worker, logging to /opt/spark-2.4.4-bin-hadoop2.7/logs/spark-root-org.apache.spark.deploy.worker.Worker-1-dn1.out
dn2: starting org.apache.spark.deploy.worker.Worker, logging to /opt/spark-2.4.4-bin-hadoop2.7/logs/spark-root-org.apache.spark.deploy.worker.Worker-1-dn2.out
接着在nn节点上启动master进程,此时nn节点将被选举为active状态1
2[root@nn spark-2.4.4-bin-hadoop2.7]# ./sbin/start-master.sh
starting org.apache.spark.deploy.master.Master, logging to /opt/spark-2.4.4-bin-hadoop2.7//logs/spark-root-org.apache.spark.deploy.master.Master-1-nn.out
最后,分别在dn1和dn2节点上启动master进程,此时因nn节点已经优先成为active角色,故这两个节点虽然启动master,但会处于standby模式
通过spark web UI查看以上集群情况:
首先访问http://nn:8080
,可以看到当前nn节点为active状态且有3个alive workers
访问http://dn1:8080
,dn1节点为standby模式,而且无自己的workers
访问http://dn2:8080
,dn2节点为standby模式,而且无自己的workers
kill掉nn上master进程,观测spark 集群的master切换情况。1
2
3
4
5
6
7
8
9
10[root@nn spark-2.4.4-bin-hadoop2.7]# jps
7094 Master
7322 Jps
7019 Worker
4892 QuorumPeerMain
5853 NameNode
5933 DataNode
6253 DFSZKFailoverController
6062 JournalNode
[root@nn spark-2.4.4-bin-hadoop2.7]# kill -9 7094
访问http://dn1:8080
,dn1节点由standby变为active模式且有3个alive workers,而dn2仍然standby模式,说明HA部署正常。
9、结束
本文详细讨论了基于hadoop上搭建spark HA集群,并对执行的application做了简单的介绍,注意到,这里spark HA集群并没有引入yarn资源调度服务,后面的文章会给出配置过程。同时本文没有对spark架构及其原理做更多的探讨,相关文章也在之后给出。