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免密登录

切记,先配置主机解析记录,再配置免密登录。

  1. # 配置主机名解析记录
  2. $ cat >> /etc/hosts <<EOF
  3. 192.168.20.2 master work01
  4. 192.168.20.3 work02
  5. 192.168.20.4 work03
  6. EOF
  7. # 修改后的hosts文件发送至其他节点
  8. $ for i in 2 3;do rsync -az /etc/hosts work0${i}:/etc/;done
  9. # 下面是配置免密登录,需要在master机器上执行
  10. # 如果可以,最好在集群中所有节点都配置免密登录到集群中的其他节点
  11. # 为了方便后续群起集群,我们必须在master机器上配置免密登录到其他节点
  12. $ ssh-keygen -t rsa # 执行后一路回车
  13. $ for i in 1 2 3;do ssh-copy-id work0${i} ;done # 执行后根据提示,该输入yes输入yes,该输入密码就输入密码

修改系统限制

  1. $ mv /etc/security/limits.conf{,.bak}
  2. cat > /etc/security/limits.conf << EOF
  3. * - nofile 655360
  4. * - memlock unlimited
  5. * - stack 655360
  6. * - nproc unlimited
  7. EOF
  8. cat > /etc/sysctl.conf << EOF
  9. kernel.sysrq = 0
  10. kernel.core_uses_pid = 1
  11. fs.file-max=655360
  12. kernel.msgmnb = 65536
  13. kernel.msgmax = 65536
  14. kernel.shmmax = 68719476736
  15. kernel.shmall = 4294967296
  16. kernel.pid_max = 655360
  17. net.ipv4.tcp_tw_reuse = 1
  18. net.ipv4.tcp_tw_recycle = 0
  19. net.ipv4.tcp_max_tw_buckets = 10000
  20. net.ipv4.tcp_fin_timeout = 30
  21. net.ipv4.tcp_timestamps = 0
  22. net.ipv4.tcp_sack = 1
  23. net.ipv4.tcp_window_scaling = 1
  24. net.ipv4.tcp_ecn = 0
  25. net.ipv4.tcp_keepalive_time = 600
  26. net.ipv4.tcp_keepalive_intvl = 30
  27. net.ipv4.tcp_keepalive_probes = 3
  28. net.ipv4.tcp_max_orphans = 655360
  29. net.ipv4.tcp_max_syn_backlog = 262144
  30. net.ipv4.tcp_mem = 65536 131072 262144
  31. net.ipv4.udp_mem = 65536 131072 262144
  32. net.ipv4.tcp_rmem = 4096 87380 16777216
  33. net.ipv4.tcp_wmem = 4096 16384 16777216
  34. net.ipv4.ip_local_port_range = 1024 65535
  35. net.ipv4.route.gc_timeout = 100
  36. # 禁止icmp重定向报文
  37. net.ipv4.conf.all.accept_redirects = 0
  38. # 禁止icmp源路由
  39. net.ipv4.conf.all.accept_source_route = 0
  40. net.core.somaxconn = 65535
  41. net.core.rmem_default = 8388608
  42. net.core.wmem_default = 8388608
  43. net.core.rmem_max = 16777216
  44. net.core.wmem_max = 16777216
  45. net.core.netdev_max_backlog = 262144
  46. vm.swappiness = 10
  47. vm.overcommit_memory = 1
  48. vm.max_map_count = 262144
  49. EOF
  50. sysctl -p
  51. #将修改后的文件发送至其他节点
  52. $ for i in 2 3;do rsync -az /etc/security/limits.conf work0${i}:/etc/security/;done
  53. $ for i in 2 3;do rsync -az /etc/sysctl.conf work0${i}:/etc/;done
  54. # 其余节点需执行下面命令刷新内核参数
  55. $ sysctl -p

配置jdk

自行去oracle官网下载java包 jdk-8u261-linux-x64.tar.gz ,然后上传至服务器。

配置jdk环境的操作,是需要在所有节点进行的。

  1. $ mkdir /apps/usr -p && systemctl stop firewalld && systemctl disable firewalld && setenforce 0
  2. $ tar zxf jdk-8u261-linux-x64.tar.gz -C /apps/usr/
  3. $ ln -sf /apps/usr/jdk1.8.0_261 /apps/usr/jdk
  4. $ cat >> /etc/profile << EOF
  5. export JAVA_HOME=/apps/usr/jdk
  6. export CLASSPATH=\$JAVA_HOME/lib
  7. export PATH=\$JAVA_HOME/bin:\$PATH
  8. EOF
  9. $ source /etc/profile
  10. $ java -version # 查看版本信息
  11. java version "1.8.0_261"
  12. Java(TM) SE Runtime Environment (build 1.8.0_261-b12)
  13. Java HotSpot(TM) 64-Bit Server VM (build 25.261-b12, mixed mode)

配置ntp时间同步

在hadoop01配置时间服务器,其他客户端制定定时任务即可。

  1. $ yum -y install ntp
  2. $ vim /etc/ntp.conf # 修改配置文件
  3. # 找到(17行左右):
  4. #restrict 192.168.1.0 mask 255.255.255.0 nomodify notrap
  5. # 改为(网段是你自己的网段,表示允许哪个网段的客户端来同步时间):
  6. restrict 192.168.20.0 mask 255.255.255.0 nomodify notrap
  7. # 找到
  8. server 0.centos.pool.ntp.org iburst
  9. server 1.centos.pool.ntp.org iburst
  10. server 2.centos.pool.ntp.org iburst
  11. server 3.centos.pool.ntp.org iburst
  12. # 将其注释掉,表示不使用互联网上的时间同步服务器
  13. #server 0.centos.pool.ntp.org iburst
  14. #server 1.centos.pool.ntp.org iburst
  15. #server 2.centos.pool.ntp.org iburst
  16. #server 3.centos.pool.ntp.org iburst
  17. # 末尾追加
  18. server 127.127.1.0
  19. fudge 127.127.1.0 stratum 5
  20. # 在上级时钟源失效时,NTP会使用127.127.1.0的本地时钟,将local时间作为ntp服务器时间提供给ntp客户端。
  21. # NTP把本地主机的时钟也看作外部时钟源来处理,分配的地址是127.127.1.0
  22. # 让硬件时间和系统时间一起同步
  23. $ echo 'SYNC_HWCLOCK=yes' >> /etc/sysconfig/ntpd
  24. # 重启ntp服务器生效
  25. $ systemctl restart ntpd && systemctl enable ntpd
  26. # 配置其他客户端定时同步时间(哪些机器要同步上面时间服务器的时间,就进行以下配置)
  27. $ yum -y install ntp
  28. $ crontab -e # 写入以下定时任务
  29. */5 * * * * /usr/sbin/ntpdate 192.168.20.2 &> /dev/null

部署spark集群

部署master节点

以下操作在master机器上执行即可。

  1. $ wget https://mirrors.tuna.tsinghua.edu.cn/apache/spark/spark-3.0.1/spark-3.0.1-bin-hadoop3.2.tgz
  2. $ tar zxf spark-3.0.1-bin-hadoop3.2.tgz -C /apps/usr/
  3. $ cd /apps/usr/spark-3.0.1-bin-hadoop3.2/conf/
  4. # slaves文件中写入所有work节点的主机名(此主机名是写在hosts文件中,可以解析的)
  5. $ cat > slaves << EOF
  6. work01
  7. work02
  8. work03
  9. EOF
  10. # 修改变量文件
  11. $ cat > spark-env.sh << EOF
  12. export JAVA_HOME=/apps/usr/jdk
  13. SPARK_MASTER_HOST=master
  14. SPARK_MASTER_PORT=7077
  15. EOF

注:关于spark-env.sh文件中支持的其他变量选项,请参考官方文档,其中有个SPARK_MASTER_OPTSSPARK_WORKER_PORT需要说明下如何配置:

Spark概念及Standalone模式集群部署 - 图1

Spark概念及Standalone模式集群部署 - 图2

上图分别罗列出了SPARK_MASTER_OPTSSPARK_WORKER_PORT所支持的配置选项,那么如何配置到spark-env.sh文件中呢?请参考如下格式:

  1. SPARK_WORKER_OPTS=”-Dspark.worker.cleanup.enabled=true Dspark.workder.cleanup.interval=1200

至于各个选项的含义,还请移步官方文档

配置历史服务

由于spark-shell停止掉后,集群监控页面就看不到历史任务的运行情况,所以一般都配置历史服务器记录任务运行情况。

由于我这里没有配置hdfs服务,所以历史服务就不去真正的启动了。如果你有hdfs服务,可以使其正常启动。

  1. $ cd /apps/usr/spark-3.0.1-bin-hadoop3.2/conf
  2. $ cp spark-defaults.conf.template spark-defaults.conf
  3. $ vim spark-defaults.conf # 开启如下选项
  4. spark.eventLog.enabled true
  5. spark.eventLog.dir hdfs://namenode:9000/spark_log
  6. #注:需要启动hadoop集群,HDFS上的directory目录需要提前存在。
  7. $ vim spark-env.sh # 修改spark-env配置文件,添加日志配置
  8. export SPARK_HISTORY_OPTS="
  9. -Dspark.history.ui.port=18080
  10. -Dspark.history.fs.logDirectory=hdfs://namenode:9000/history
  11. -Dspark.history.retainedApplications=30"
  12. # spark.history.ui.port:指定web ui访问的端口号
  13. # spark.history.fs.logDirectory:指定历史服务器日志存储路径。
  14. # spark.history.retainedApplications=30:指定保存Application历史记录的个数,\
  15. # 如果超过这个值,旧的应用程序信息将被删除,这个是内存中的应用数,而不是页面上显示的应用数。
  16. # 分发spark安装目录至其他work节点
  17. $ 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节点。

  1. $ cd /apps/usr/spark-3.0.1-bin-hadoop3.2/sbin/
  2. $ ./start-all.sh
  3. 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
  4. 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
  5. 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
  6. 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
  7. # 查看master启动的角色
  8. $ jps
  9. 7895 Worker
  10. 7959 Jps
  11. 7820 Master
  12. # 查看work02节点启动的角色
  13. $ jps
  14. 7763 Jps
  15. 7701 Worker
  16. # 查看work03节点启动的角色
  17. $ jps
  18. 7896 Jps
  19. 7834 Worker

验证集群

查看master资源监控web ui界面

访问master节点的 8080端口,如下:

Spark概念及Standalone模式集群部署 - 图3

可以看到以上页面,则表示集群已经部署完毕了。

提交应用至集群

  1. $ cd /apps/usr/spark-3.0.1-bin-hadoop3.2/
  2. $ bin/spark-submit \
  3. --class org.apache.spark.examples.SparkPi \
  4. --master spark://master:7077 \
  5. ./examples/jars/spark-examples_2.12-3.0.1.jar \
  6. 10
  7. # --class:表示要执行程序的主类
  8. # --master:表示指定master的监听地址
  9. # spark-examples_2.12-3.0.1.jar:表示运行类所在的jar包
  10. # 10:表示程序的入口参数,用于设定当前应用的任务数量。

以上应用提交后,屏幕会输出如下:

Spark概念及Standalone模式集群部署 - 图4

而master的web ui界面,也能查看到你刚才提交的应用程序执行情况,如下:

Spark概念及Standalone模式集群部署 - 图5

启动历史服务器

  1. $ cd /apps/usr/spark-3.0.1-bin-hadoop3.2/sbin/
  2. $ ./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的集群环境。

停止集群

  1. $ cd /apps/usr/spark-3.0.1-bin-hadoop3.2/sbin/
  2. $ ./stop-all.sh

部署zookeeper集群

以下操作只需在master01上执行,然后将修改好的配置文件发送至其他节点,在生产中,如果说想减轻机器压力,或者说机器配置没那么高,可以将Zookeeper集群单独部署到其他节点,只要保证指定的地址无误即可。

  1. wget http://archive.apache.org/dist/zookeeper/zookeeper-3.4.14/zookeeper-3.4.14.tar.gz
  2. tar zxf zookeeper-3.4.14.tar.gz -C /apps/usr/
  3. ln -sf /apps/usr/zookeeper-3.4.14 /apps/usr/zk
  4. # 配置
  5. mkdir /apps/usr/zk/data
  6. echo 1 > /apps/usr/zk/data/myid
  7. cat > /apps/usr/zk/conf/zoo.cfg << EOF
  8. dataDir=/apps/usr/zk/data
  9. clientPort=2181
  10. maxClientCnxns=0
  11. tickTime=2000
  12. initLimit=10
  13. syncLimit=5
  14. quorumListenOnAllIPs=true
  15. server.1=work01:2888:3888
  16. server.2=work02:2888:3888
  17. server.3=work03:2888:3888
  18. EOF
  19. # 上面的server可以指定IP+端口
  20. # 注意,server.x :x表示节点id,必须和实际IP对应上,如果不对应,最后查看集群状态时,大概率会看到如下:
  21. # $ /apps/usr/zk/bin/zkServer.sh status
  22. # ZooKeeper JMX enabled by default
  23. # Using config: /apps/usr/zk/bin/../conf/zoo.cfg
  24. # Error contacting service. It is probably not running. # 尽管端口都在监听,但状态是没运行
  25. # 现在接着配置
  26. # 将zookeeper目录发送至其他节点
  27. $ for i in 2 3;do rsync -az /apps/usr/zookeeper-3.4.14 work0${i}:/apps/usr/;done
  28. # 启动work01节点的zookeeper
  29. $ /apps/usr/zk/bin/zkServer.sh start
  30. # 只有leader才会监听28888
  31. ss -lnpt | egrep '2181|3888|2888'

修改work02节点的配置文件

  1. ln -sf /apps/usr/zookeeper-3.4.14/ /apps/usr/zk
  2. echo 2 > /apps/usr/zk/data/myid

修改workp03节点的配置文件

  1. ln -sf /apps/usr/zookeeper-3.4.14/ /apps/usr/zk
  2. echo 3 > /apps/usr/zk/data/myid

执行以下指令启动各个zookeeper节点

  1. $ /apps/usr/zk/bin/zkServer.sh start
  2. ss -lnpt | egrep '2181|3888|2888' # 确定端口在监听
  3. # 别忘了,只有leader才会监听2888
  4. $ /apps/usr/zk/bin/zkServer.sh status # 查看集群状态(应该有一个leader,两个follower)
  5. ZooKeeper JMX enabled by default
  6. Using config: /apps/usr/zk/bin/../conf/zoo.cfg
  7. Mode: follower

至此,zookeeper集群部署完成。

配置spark-env

注:以下操作在上面的master节点执行即可。

  1. $ cd /apps/usr/spark-3.0.1-bin-hadoop3.2/conf/
  2. $ vim spark-env.sh
  3. # 注释下面两行原有配置
  4. #SPARK_MASTER_HOST=master
  5. #SPARK_MASTER_PORT=7077
  6. # 写入以下配置
  7. SPARK_MASTER_WEBUI_PORT=8989
  8. export SPARK_DAEMON_JAVA_OPTS="
  9. -Dspark.deploy.recoveryMode=ZOOKEEPER
  10. -Dspark.deploy.zookeeper.url=work01,work02,work03
  11. -Dspark.deploy.zookeeper.dir=/spark"
  12. # -Dspark.deploy.zookeeper.url:指定zookeeper的IP或可解析的主机名。

分发配置文件并启动集群

  1. $ 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
  2. # 由于work02也被规划为了master,所以需要配置work02可以免密登录到其他节点
  3. # 在work02上执行如下操作
  4. $ ssh-keygen -t rsa # 执行后一路回车
  5. $ for i in 1 2 3;do ssh-copy-id work0${i} ;done # 执行后根据提示,该输入yes输入yes,该输入密码就输入密码
  6. # 启动集群(在master01执行)
  7. $ cd /apps/usr/spark-3.0.1-bin-hadoop3.2/sbin/
  8. $ ./start-all.sh # 可以看到,只是启动了一个master,三个work
  9. 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
  10. 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
  11. 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
  12. 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的启动命令就是下面这样的:

Spark概念及Standalone模式集群部署 - 图6

对,—hosts 选项会指定为你当前的主机名,也就是说,你必须保证参与集群的节点,可以正确的解析你当前的实际主机名,否则,集群无法建立成功。

访问spark ui界面

我不知道为啥下面会有重复的work节点,并且是无效状态的,心碎…..(最后 意外之喜 这一小节,有解决办法)

Spark概念及Standalone模式集群部署 - 图7

启动第二个master节点

  1. # 到第二个节点master02,启动其master角色
  2. cd /apps/usr/spark-3.0.1-bin-hadoop3.2/sbin
  3. ./start-master.sh

确认两个master状态

现在分别访问两个master的8989端口,即可看到其状态分别为:active和standby,如下:

Spark概念及Standalone模式集群部署 - 图8

Spark概念及Standalone模式集群部署 - 图9

验证高可用性

手动宕掉当前处于active状态的master节点,然后再次查看:

  1. cd /apps/usr/spark-3.0.1-bin-hadoop3.2/sbin
  2. ./stop-master.sh

大约等待一分钟后,即可看到原本处于standby状态的节点变成了active状态,如下:

Spark概念及Standalone模式集群部署 - 图10

意外之喜

当我再次启动手动宕掉的节点后,发现之前重复的无效work竟然消失了,如下:

Spark概念及Standalone模式集群部署 - 图11