title: Spark概念及Standalone模式集群部署 #标题tags: spark #标签
date: 2021-01-20
categories: Hadoop # 分类
用于记录下spark相关概念及Standalone模式集群部署。
参考:
spark是什么
spark是一种由scala语言开发的基于内存的快速、通用、可扩展的大数据分析计算引擎。它可以独立部署,也可以和hadoop集群集成,并取代mapreduce。spark主要功能是用于数据计算,所以spark一直被认为是hadoop框架的升级版。
spark or hadoop,如何选择?
hadoop mapreduce 由于其设计初衷并不是为了满足循环迭代式数据流处理(适用于一次性数据计算,即读取数据===》进行逻辑操作===》将处理后的结果重新存储到文件中,这个过程即被称为一次性数据计算),因此在多并行运行的数据可复用场景(如:机器学习、图挖掘算法、交互式数据挖掘算法)中存在诸多计算效率等问题。所以spark应运而生,spark就是在传统的mapreduce计算框架的基础上,利用其计算过程的优化,从而大大加快了数据分析、挖掘的运行和读写速度,并将计算单元缩小到更适合并行计算和重复使用的RDD计算模型。
spark和hadoop的根本差异式多个作业之间的数据通信问题:spark多个作业之间数据通信是基于内存,而hadoop是基于磁盘。
环境准备
OS | hostname / roles | IP |
---|---|---|
Centos 7.6 | master/work01 | 192.168.20.2 |
Centos 7.6 | work02 | 192.168.20.3 |
Centos 7.6 | work03 | 192.168.20.4 |
注:192.168.20.2即是master节点,也是work节点。
配置ssh免密登录
切记,先配置主机解析记录,再配置免密登录。
# 配置主机名解析记录
$ cat >> /etc/hosts <<EOF
192.168.20.2 master work01
192.168.20.3 work02
192.168.20.4 work03
EOF
# 修改后的hosts文件发送至其他节点
$ for i in 2 3;do rsync -az /etc/hosts work0${i}:/etc/;done
# 下面是配置免密登录,需要在master机器上执行
# 如果可以,最好在集群中所有节点都配置免密登录到集群中的其他节点
# 为了方便后续群起集群,我们必须在master机器上配置免密登录到其他节点
$ ssh-keygen -t rsa # 执行后一路回车
$ for i in 1 2 3;do ssh-copy-id work0${i} ;done # 执行后根据提示,该输入yes输入yes,该输入密码就输入密码
修改系统限制
$ mv /etc/security/limits.conf{,.bak}
cat > /etc/security/limits.conf << EOF
* - nofile 655360
* - memlock unlimited
* - stack 655360
* - nproc unlimited
EOF
cat > /etc/sysctl.conf << EOF
kernel.sysrq = 0
kernel.core_uses_pid = 1
fs.file-max=655360
kernel.msgmnb = 65536
kernel.msgmax = 65536
kernel.shmmax = 68719476736
kernel.shmall = 4294967296
kernel.pid_max = 655360
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 0
net.ipv4.tcp_max_tw_buckets = 10000
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_sack = 1
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_ecn = 0
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_max_orphans = 655360
net.ipv4.tcp_max_syn_backlog = 262144
net.ipv4.tcp_mem = 65536 131072 262144
net.ipv4.udp_mem = 65536 131072 262144
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 16384 16777216
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.route.gc_timeout = 100
# 禁止icmp重定向报文
net.ipv4.conf.all.accept_redirects = 0
# 禁止icmp源路由
net.ipv4.conf.all.accept_source_route = 0
net.core.somaxconn = 65535
net.core.rmem_default = 8388608
net.core.wmem_default = 8388608
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.netdev_max_backlog = 262144
vm.swappiness = 10
vm.overcommit_memory = 1
vm.max_map_count = 262144
EOF
sysctl -p
#将修改后的文件发送至其他节点
$ for i in 2 3;do rsync -az /etc/security/limits.conf work0${i}:/etc/security/;done
$ for i in 2 3;do rsync -az /etc/sysctl.conf work0${i}:/etc/;done
# 其余节点需执行下面命令刷新内核参数
$ sysctl -p
配置jdk
自行去oracle官网下载java包 jdk-8u261-linux-x64.tar.gz ,然后上传至服务器。
配置jdk环境的操作,是需要在所有节点进行的。
$ mkdir /apps/usr -p && systemctl stop firewalld && systemctl disable firewalld && setenforce 0
$ tar zxf jdk-8u261-linux-x64.tar.gz -C /apps/usr/
$ ln -sf /apps/usr/jdk1.8.0_261 /apps/usr/jdk
$ cat >> /etc/profile << EOF
export JAVA_HOME=/apps/usr/jdk
export CLASSPATH=\$JAVA_HOME/lib
export PATH=\$JAVA_HOME/bin:\$PATH
EOF
$ source /etc/profile
$ java -version # 查看版本信息
java version "1.8.0_261"
Java(TM) SE Runtime Environment (build 1.8.0_261-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.261-b12, mixed mode)
配置ntp时间同步
在hadoop01配置时间服务器,其他客户端制定定时任务即可。
$ yum -y install ntp
$ vim /etc/ntp.conf # 修改配置文件
# 找到(17行左右):
#restrict 192.168.1.0 mask 255.255.255.0 nomodify notrap
# 改为(网段是你自己的网段,表示允许哪个网段的客户端来同步时间):
restrict 192.168.20.0 mask 255.255.255.0 nomodify notrap
# 找到
server 0.centos.pool.ntp.org iburst
server 1.centos.pool.ntp.org iburst
server 2.centos.pool.ntp.org iburst
server 3.centos.pool.ntp.org iburst
# 将其注释掉,表示不使用互联网上的时间同步服务器
#server 0.centos.pool.ntp.org iburst
#server 1.centos.pool.ntp.org iburst
#server 2.centos.pool.ntp.org iburst
#server 3.centos.pool.ntp.org iburst
# 末尾追加
server 127.127.1.0
fudge 127.127.1.0 stratum 5
# 在上级时钟源失效时,NTP会使用127.127.1.0的本地时钟,将local时间作为ntp服务器时间提供给ntp客户端。
# NTP把本地主机的时钟也看作外部时钟源来处理,分配的地址是127.127.1.0
# 让硬件时间和系统时间一起同步
$ echo 'SYNC_HWCLOCK=yes' >> /etc/sysconfig/ntpd
# 重启ntp服务器生效
$ systemctl restart ntpd && systemctl enable ntpd
# 配置其他客户端定时同步时间(哪些机器要同步上面时间服务器的时间,就进行以下配置)
$ yum -y install ntp
$ crontab -e # 写入以下定时任务
*/5 * * * * /usr/sbin/ntpdate 192.168.20.2 &> /dev/null
部署spark集群
部署master节点
以下操作在master机器上执行即可。
$ wget https://mirrors.tuna.tsinghua.edu.cn/apache/spark/spark-3.0.1/spark-3.0.1-bin-hadoop3.2.tgz
$ tar zxf spark-3.0.1-bin-hadoop3.2.tgz -C /apps/usr/
$ cd /apps/usr/spark-3.0.1-bin-hadoop3.2/conf/
# slaves文件中写入所有work节点的主机名(此主机名是写在hosts文件中,可以解析的)
$ cat > slaves << EOF
work01
work02
work03
EOF
# 修改变量文件
$ cat > spark-env.sh << EOF
export JAVA_HOME=/apps/usr/jdk
SPARK_MASTER_HOST=master
SPARK_MASTER_PORT=7077
EOF
注:关于spark-env.sh
文件中支持的其他变量选项,请参考官方文档,其中有个SPARK_MASTER_OPTS
和 SPARK_WORKER_PORT
需要说明下如何配置:
上图分别罗列出了SPARK_MASTER_OPTS
和 SPARK_WORKER_PORT
所支持的配置选项,那么如何配置到spark-env.sh
文件中呢?请参考如下格式:
SPARK_WORKER_OPTS=”-Dspark.worker.cleanup.enabled=true –Dspark.workder.cleanup.interval=1200”
至于各个选项的含义,还请移步官方文档。
配置历史服务
由于spark-shell停止掉后,集群监控页面就看不到历史任务的运行情况,所以一般都配置历史服务器记录任务运行情况。
由于我这里没有配置hdfs服务,所以历史服务就不去真正的启动了。如果你有hdfs服务,可以使其正常启动。
$ cd /apps/usr/spark-3.0.1-bin-hadoop3.2/conf
$ cp spark-defaults.conf.template spark-defaults.conf
$ vim spark-defaults.conf # 开启如下选项
spark.eventLog.enabled true
spark.eventLog.dir hdfs://namenode:9000/spark_log
#注:需要启动hadoop集群,HDFS上的directory目录需要提前存在。
$ vim spark-env.sh # 修改spark-env配置文件,添加日志配置
export SPARK_HISTORY_OPTS="
-Dspark.history.ui.port=18080
-Dspark.history.fs.logDirectory=hdfs://namenode:9000/history
-Dspark.history.retainedApplications=30"
# spark.history.ui.port:指定web ui访问的端口号
# spark.history.fs.logDirectory:指定历史服务器日志存储路径。
# spark.history.retainedApplications=30:指定保存Application历史记录的个数,\
# 如果超过这个值,旧的应用程序信息将被删除,这个是内存中的应用数,而不是页面上显示的应用数。
# 分发spark安装目录至其他work节点
$ for i in 2 3;do rsync -az /apps/usr/spark-3.0.1-bin-hadoop3.2 work0${i}:/apps/usr/;done
启动spark集群
只需在master节点上执行 start-all.sh脚本即可,前提是master节点可以免密登录到其他work节点。
$ cd /apps/usr/spark-3.0.1-bin-hadoop3.2/sbin/
$ ./start-all.sh
starting org.apache.spark.deploy.master.Master, logging to /apps/usr/spark-3.0.1-bin-hadoop3.2/logs/spark-root-org.apache.spark.deploy.master.Master-1-lv.out
work03: starting org.apache.spark.deploy.worker.Worker, logging to /apps/usr/spark-3.0.1-bin-hadoop3.2/logs/spark-root-org.apache.spark.deploy.worker.Worker-1-lv.out
work01: starting org.apache.spark.deploy.worker.Worker, logging to /apps/usr/spark-3.0.1-bin-hadoop3.2/logs/spark-root-org.apache.spark.deploy.worker.Worker-1-lv.out
work02: starting org.apache.spark.deploy.worker.Worker, logging to /apps/usr/spark-3.0.1-bin-hadoop3.2/logs/spark-root-org.apache.spark.deploy.worker.Worker-1-lv.out
# 查看master启动的角色
$ jps
7895 Worker
7959 Jps
7820 Master
# 查看work02节点启动的角色
$ jps
7763 Jps
7701 Worker
# 查看work03节点启动的角色
$ jps
7896 Jps
7834 Worker
验证集群
查看master资源监控web ui界面
访问master节点的 8080端口,如下:
可以看到以上页面,则表示集群已经部署完毕了。
提交应用至集群
$ cd /apps/usr/spark-3.0.1-bin-hadoop3.2/
$ bin/spark-submit \
--class org.apache.spark.examples.SparkPi \
--master spark://master:7077 \
./examples/jars/spark-examples_2.12-3.0.1.jar \
10
# --class:表示要执行程序的主类
# --master:表示指定master的监听地址
# spark-examples_2.12-3.0.1.jar:表示运行类所在的jar包
# 10:表示程序的入口参数,用于设定当前应用的任务数量。
以上应用提交后,屏幕会输出如下:
而master的web ui界面,也能查看到你刚才提交的应用程序执行情况,如下:
启动历史服务器
$ cd /apps/usr/spark-3.0.1-bin-hadoop3.2/sbin/
$ ./start-history-server.sh
由于我这里没有配置hdfs服务,所以历史服务就不去真正的启动了。
spark集群配置高可用
在上面部署的集群中,只有一个master,所以会存在单点故障问题,所以为了解决单点故障问题,需要在集群中配置多个master节点,一旦处于活跃状态的master发生故障,由备用master提供服务,保证作业可以继续执行。这里的高可用,一般采用zookeeper来实现,高可用的集群规划如下:
OS | roles | IP |
---|---|---|
Centos 7.6 | master01 / work01 / zookeeper | 192.168.20.2 |
Centos 7.6 | master02 / work02 / zookeeper | 192.168.20.3 |
Centos 7.6 | work03 /zookeeper | 192.168.20.4 |
注,接下来的操作,还是基于上面部署的单master的集群环境。
停止集群
$ cd /apps/usr/spark-3.0.1-bin-hadoop3.2/sbin/
$ ./stop-all.sh
部署zookeeper集群
以下操作只需在master01上执行,然后将修改好的配置文件发送至其他节点,在生产中,如果说想减轻机器压力,或者说机器配置没那么高,可以将Zookeeper集群单独部署到其他节点,只要保证指定的地址无误即可。
wget http://archive.apache.org/dist/zookeeper/zookeeper-3.4.14/zookeeper-3.4.14.tar.gz
tar zxf zookeeper-3.4.14.tar.gz -C /apps/usr/
ln -sf /apps/usr/zookeeper-3.4.14 /apps/usr/zk
# 配置
mkdir /apps/usr/zk/data
echo 1 > /apps/usr/zk/data/myid
cat > /apps/usr/zk/conf/zoo.cfg << EOF
dataDir=/apps/usr/zk/data
clientPort=2181
maxClientCnxns=0
tickTime=2000
initLimit=10
syncLimit=5
quorumListenOnAllIPs=true
server.1=work01:2888:3888
server.2=work02:2888:3888
server.3=work03:2888:3888
EOF
# 上面的server可以指定IP+端口
# 注意,server.x :x表示节点id,必须和实际IP对应上,如果不对应,最后查看集群状态时,大概率会看到如下:
# $ /apps/usr/zk/bin/zkServer.sh status
# ZooKeeper JMX enabled by default
# Using config: /apps/usr/zk/bin/../conf/zoo.cfg
# Error contacting service. It is probably not running. # 尽管端口都在监听,但状态是没运行
# 现在接着配置
# 将zookeeper目录发送至其他节点
$ for i in 2 3;do rsync -az /apps/usr/zookeeper-3.4.14 work0${i}:/apps/usr/;done
# 启动work01节点的zookeeper
$ /apps/usr/zk/bin/zkServer.sh start
# 只有leader才会监听28888
ss -lnpt | egrep '2181|3888|2888'
修改work02节点的配置文件
ln -sf /apps/usr/zookeeper-3.4.14/ /apps/usr/zk
echo 2 > /apps/usr/zk/data/myid
修改workp03节点的配置文件
ln -sf /apps/usr/zookeeper-3.4.14/ /apps/usr/zk
echo 3 > /apps/usr/zk/data/myid
执行以下指令启动各个zookeeper节点
$ /apps/usr/zk/bin/zkServer.sh start
ss -lnpt | egrep '2181|3888|2888' # 确定端口在监听
# 别忘了,只有leader才会监听2888
$ /apps/usr/zk/bin/zkServer.sh status # 查看集群状态(应该有一个leader,两个follower)
ZooKeeper JMX enabled by default
Using config: /apps/usr/zk/bin/../conf/zoo.cfg
Mode: follower
至此,zookeeper集群部署完成。
配置spark-env
注:以下操作在上面的master节点执行即可。
$ cd /apps/usr/spark-3.0.1-bin-hadoop3.2/conf/
$ vim spark-env.sh
# 注释下面两行原有配置
#SPARK_MASTER_HOST=master
#SPARK_MASTER_PORT=7077
# 写入以下配置
SPARK_MASTER_WEBUI_PORT=8989
export SPARK_DAEMON_JAVA_OPTS="
-Dspark.deploy.recoveryMode=ZOOKEEPER
-Dspark.deploy.zookeeper.url=work01,work02,work03
-Dspark.deploy.zookeeper.dir=/spark"
# -Dspark.deploy.zookeeper.url:指定zookeeper的IP或可解析的主机名。
分发配置文件并启动集群
$ for i in 2 3;do rsync -az /apps/usr/spark-3.0.1-bin-hadoop3.2/conf/ work0${i}:/apps/usr/spark-3.0.1-bin-hadoop3.2/conf/;done
# 由于work02也被规划为了master,所以需要配置work02可以免密登录到其他节点
# 在work02上执行如下操作
$ ssh-keygen -t rsa # 执行后一路回车
$ for i in 1 2 3;do ssh-copy-id work0${i} ;done # 执行后根据提示,该输入yes输入yes,该输入密码就输入密码
# 启动集群(在master01执行)
$ cd /apps/usr/spark-3.0.1-bin-hadoop3.2/sbin/
$ ./start-all.sh # 可以看到,只是启动了一个master,三个work
starting org.apache.spark.deploy.master.Master, logging to /apps/usr/spark-3.0.1-bin-hadoop3.2/logs/spark-root-org.apache.spark.deploy.master.Master-1-lv.out
work03: starting org.apache.spark.deploy.worker.Worker, logging to /apps/usr/spark-3.0.1-bin-hadoop3.2/logs/spark-root-org.apache.spark.deploy.worker.Worker-1-lv.out
work02: starting org.apache.spark.deploy.worker.Worker, logging to /apps/usr/spark-3.0.1-bin-hadoop3.2/logs/spark-root-org.apache.spark.deploy.worker.Worker-1-lv.out
work01: starting org.apache.spark.deploy.worker.Worker, logging to /apps/usr/spark-3.0.1-bin-hadoop3.2/logs/spark-root-org.apache.spark.deploy.worker.Worker-1-lv.out
注意:在启动时,可能会踩到一个坑,就是你hosts文件中的解析记录,和你实际的主机名不一致,那么这样,你的集群是无法启动成功的,因为我们取消掉了SPARK_MASTER_HOST=master
这个配置,则默认master的启动命令就是下面这样的:
对,—hosts 选项会指定为你当前的主机名,也就是说,你必须保证参与集群的节点,可以正确的解析你当前的实际主机名,否则,集群无法建立成功。
访问spark ui界面
我不知道为啥下面会有重复的work节点,并且是无效状态的,心碎…..(最后 意外之喜 这一小节,有解决办法)
启动第二个master节点
# 到第二个节点master02,启动其master角色
cd /apps/usr/spark-3.0.1-bin-hadoop3.2/sbin
./start-master.sh
确认两个master状态
现在分别访问两个master的8989端口,即可看到其状态分别为:active和standby,如下:
验证高可用性
手动宕掉当前处于active
状态的master节点,然后再次查看:
cd /apps/usr/spark-3.0.1-bin-hadoop3.2/sbin
./stop-master.sh
大约等待一分钟后,即可看到原本处于standby
状态的节点变成了active
状态,如下:
意外之喜
当我再次启动手动宕掉的节点后,发现之前重复的无效work竟然消失了,如下: