转载请注明出处,谢谢合作~
部署的子模块暂时只提供 Standalone 和 Yarn,k8s 我不会,Mesos 没用过
集群部署
集群模式概览
本文档对 Spark 如何在集群上运行作一个简单的介绍,来帮助理解其中所包含的各个组件。如何在集群上启动应用程序参见文档 application submission guide。
组件
Spark 应用程序在集群中运行时,表现为一组进程集,由主程序(也被叫做 driver program)中的 SparkContext
对象作协调。
特别是,当程序运行在一个集群上时,SparkContext
对象可以和不同类型的集群管理器(Spark 自己的独立集群管理器,Mesos 或者 Yarn)进行连接,为应用程序分配需要的资源。一旦连接成功,Spark 就向集群中的节点申请进行计算和数据存储的 executor。接下来,driver 将应用程序代码(由 SparkContext
传递的 JAR 文件或者 Python 文件)发送给 executor,最后,SparkContext
发送子任务给 executor 运行。
对于这种架构有一些有用的点需要注意:
- 每个应用程序都有属于自己的 executor 进程,在整个应用程序运行期间一直待命,启动多个线程运行子任务。这种方式可以在调度端(每个 driver 调度自己的子任务)和执行端(不同应用程序的子任务运行在不同的 JVM 内)同时做到多个应用程序之间的资源隔离。然而,这也意味着除非写出到外部存储系统,数据无法在不同的 Spark 应用程序(不同的
SparkContext
实例)之间共享。 - 下层的集群管理器对 Spark 应用程序来说是透明的。只要应用程序还能够申请到 executor 进程,这些进程之间还可以互相通信,就可以轻松的在一个支持其他应用类型的集群管理器上运行(例如,Mesos/YARN)。
- driver 程序必须监听和接收所属 executor 进程在整个生命周期内传递的消息(参见 spark.driver.port in the network config section)。所以,driver 程序对于 worker 节点必须是网络可达的。
- 因为 driver 在集群中调度子任务,它所运行的节点应该和 worker 节点足够近,最好在同一个网络平面内。如果需要向远程集群发送请求,最好通过 RPC 的方式来运行 driver,就近运行 driver 及其 executor,而不是让 driver 程序离 worker 节点很远。
集群模式类型
目前支持一下几种集群管理器:
- Standalone – Spark 中包含的一个简单的集群管理器,可以轻松部署管理一个集群。
- Apache Mesos – 一个通用的集群管理器,也可以运行 Hadoop MapReduce 应用程序。
- Hadoop YARN – Hadoop 2 中的集群资源管理器。
- Kubernetes – 一个开源的容器编排工具,可以自动部署,弹性扩容,容器化的管理应用程序。
还有一个第三方项目(非 Spark 项目提供支持)提供了将 Nomad 作为集群管理器的支持。
提交应用程序
可以通过 spark-submit
脚本提交应用程序到任何类型的集群上。详情参见 application submission guide。
监控
每一个 driver 程序都有自己的 web UI,通常端口是 4040,展示了正在运行的子任务,executor 和存储管理的信息,可以通过浏览器输入地址 http://<driver-node>:4040
来访问。监控指南文档还介绍了其他的监控方式。
Each driver program has a web UI, typically on port 4040, that displays information about running tasks, executors, and storage usage. Simply go to http://<driver-node>:4040
in a web browser to access this UI. The monitoring guide also describes other monitoring options.
作业调度
Spark 对应用程序间(在集群资源管理器层面)以及应用程序内部(如果多个计算任务在一个 SparkContext 中同时运行)都提供了资源分配的控制。详情参见 job scheduling overview。
术语
下面的表格总结了集群模式中用到的概念术语:
Term | Meaning |
---|---|
Application | 构建于 Spark 之上的用户应用程序,由一个 driver 程序和多个在集群上运行的 executor 构成。 |
Application jar | 包含 Spark 应用程序的 Jar 文件。在一些场景下,用户可能需要创建一个「超级 Jar 文件」,其中包含应用程序和相关的依赖,但是其中不应该加入 Hadoop 或者 Spark 相关的依赖库,这些依赖会在运行时由 Spark 提供。 |
Driver program | 运行应用程序 main 方法的进程,其中会创建 SparkContext 对象。 |
Cluster manager | 一个外部的管理集群资源的服务。(例如,独立集群管理器,Mesos,Yarn) |
Deploy mode | 区分 driver 进程在哪里运行。在「cluster」模式下,Spark 会在集群内启动 driver 程序,在「client」模式下,Spark 会在集群外启动 driver 程序。 |
Worker node | 集群中可以运行应用程序的节点。 |
Executor | 在 worker 节点启动的应用程序进程,执行子任务,并将计算数据保存在内存或者硬盘上。每个应用程序都有自己的 executor。 |
Task | 发送到 executor 执行的一个计算单元。 |
Job | 一组并行计算的子任务构成工作单元,由 Spark 中的 action 算子(例如,save ,collect )触发;可以在 driver 的日志中观察到此术语。 |
Stage | 每一个 job 都会被划分为小的子任务集,被叫做 stage,它们之间有相互依赖的关系(类似于 MapReduce 中的 map 和 reduce 阶段);可以在 driver 的日志中观察到此术语。 |
提交应用程序
Spark bin
目录下的 spark-submit
脚本用来将一个应用程序提交到集群。该脚本可以通过统一的接口使用所有 Spark 支持的集群管理器(cluster managers),所以不需要为每个应用程序作单独配置。
打包应用程序依赖
如果你的代码依赖其他项目,需要将这些依赖于自己的应用程序打包在一起,Spark 会将 Jar 文件分发到集群上。可以通过创建一个组合 Jar 文件(或者「超级」Jar 文件)来实现,sbt 和 Maven 都有组合插件。在创建组合 Jar 文件时,请将 Spark 和 Hadoop 相关的依赖标记为 provided
,这些不需要被打包在一起,因为集群管理器在运行时会提供。一旦打包好了组合 Jar 文件,可以调用 bin/spark-submit
脚本来传递 Jar 文件,如下所示。
对于 Python,可以使用 spark-submit
脚本的 --py-files
参数添加 .py
,.zip
或者 .egg
文件来分发应用程序。如果依赖多个 Python 文件,建议将它们压缩为 .zip
或者 .egg
文件。
使用 spark-submit 脚本启动应用程序
一旦打包好一个应用程序,就可以使用 bin/spark-submit
脚本来启动。该脚本会处理好添加 Spark 相关的依赖,能够支持不同的集群管理器和支持的部署模式:
./bin/spark-submit \
--class <main-class> \
--master <master-url> \
--deploy-mode <deploy-mode> \
--conf <key>=<value> \
... # other options
<application-jar> \
[application-arguments]
一些常用的参数:
-
--class
:应用程序入口主类(例如org.apache.spark.examples.SparkPi
) -
--master
:集群地址 master URL(例如spark://23.195.26.187:7077
) -
--deploy-mode
:是否将 driver 进程部署到集群 worker 节点(cluster
),或者作为客户端在集群外部运行(client
),默认为client
† -
--conf
:自定义的 Spark 配置项,格式为 key=value。对于包含空格的值,需要添加双引号 “key=value”,多个配置项应该分开设置(例如--conf <key>=<value> --conf <key2>=<value2>
) -
application-jar
:包含应用程序和依赖的 Jar 文件路径。URL 地址必须在集群中全局可见,例如,一个hdfs://
路径或者一个在所有节点都存在的file://
路径 -
application-arguments
:传递给应用程序主类的参数,如果有的话
†一个常用的部署策略就是从一个与 worker 节点物理上连接的网关节点上提交应用程序(例如,在一个独立 EC2 集群上的 Master 节点)。此时,就是适合采用 client
部署模式,在 client
模式下,driver 程序会作为集群的客户端的角色由 spark-submit
脚本提交。应用程序的输入和输出被定向到控制台,所以,这种模式很适合 REPL(例如,Spark shell)。
另外,如果从一个离 worker 节点很远的机器上提交应用程序(例如,本地或者自己的笔记本),通常使用 cluster
模式来最小化 driver 和 executor 之间的网络延迟。目前,独立集群部署方式不支持 Python 应用的集群提交模式。
对于 Python 应用程序,请将原本在 <application-jar>
位置的 Jar 文件替换为 .py
文件,通过 --py-files
参数添加 .zip
,.egg
或者 .py
文件。
有一些与集群管理器(cluster manager)相关的特定选项,例如,对于 Spark 独立集群(Spark standalone cluster)部署模式下的 cluster
提交模式,可以指定 --supervise
参数来让 driver 进程在异常退出的情况下自动重启。可以通过 --help
参数列举出 spark-submit
脚本所有可用的参数选项。下面是一些常用的参数选项:
# Run application locally on 8 cores
./bin/spark-submit \
--class org.apache.spark.examples.SparkPi \
--master local[8] \
/path/to/examples.jar \
100
# Run on a Spark standalone cluster in client deploy mode
./bin/spark-submit \
--class org.apache.spark.examples.SparkPi \
--master spark://207.184.161.138:7077 \
--executor-memory 20G \
--total-executor-cores 100 \
/path/to/examples.jar \
1000
# Run on a Spark standalone cluster in cluster deploy mode with supervise
./bin/spark-submit \
--class org.apache.spark.examples.SparkPi \
--master spark://207.184.161.138:7077 \
--deploy-mode cluster \
--supervise \
--executor-memory 20G \
--total-executor-cores 100 \
/path/to/examples.jar \
1000
# Run on a YARN cluster
export HADOOP_CONF_DIR=XXX
./bin/spark-submit \
--class org.apache.spark.examples.SparkPi \
--master yarn \
--deploy-mode cluster \ # can be client for client mode
--executor-memory 20G \
--num-executors 50 \
/path/to/examples.jar \
1000
# Run a Python application on a Spark standalone cluster
./bin/spark-submit \
--master spark://207.184.161.138:7077 \
examples/src/main/python/pi.py \
1000
# Run on a Mesos cluster in cluster deploy mode with supervise
./bin/spark-submit \
--class org.apache.spark.examples.SparkPi \
--master mesos://207.184.161.138:7077 \
--deploy-mode cluster \
--supervise \
--executor-memory 20G \
--total-executor-cores 100 \
http://path/to/examples.jar \
1000
# Run on a Kubernetes cluster in cluster deploy mode
./bin/spark-submit \
--class org.apache.spark.examples.SparkPi \
--master k8s://xx.yy.zz.ww:443 \
--deploy-mode cluster \
--executor-memory 20G \
--num-executors 50 \
http://path/to/examples.jar \
1000
Master URLs
传递给 Spark 的 master URL 可以是以下几种格式之一:
Master URL | Meaning |
---|---|
local |
启用一个 worker 线程在本地运行 Spark 应用程序(即,没有并行计算)。 |
local[K] |
启动 K 个 worker 线程在本地运行 Spark 应用程序(最好将该值设置为运行宿主机的核数)。 |
local[K,F] |
启动 K 个 worker 线程在本地运行 Spark 应用程序,并允许 F 个线程执行失败(对该参数的解释参见 spark.task.maxFailures)。 |
local[*] |
启动本机逻辑核心数个 worker 线程在本地运行 Spark 应用程序。 |
local[*,F] |
启动本机逻辑核心数个 worker 线程在本地运行 Spark 应用程序,并允许 F 个线程执行失败。 |
spark://HOST:PORT |
连接到指定的 Spark 独立集群(Spark standalone cluster)的 master 节点。端口必须是正在使用的配置端口,默认为 7077。 |
spark://HOST1:PORT1,HOST2:PORT2 |
连接到指定的通过 Zookeeper 开启了高可用的 Spark 独立集群(Spark standalone cluster with standby masters with Zookeeper)。端口必须是正在使用的配置端口,默认为 7077。 |
mesos://HOST:PORT |
连接到指定的 Mesos 集群。端口必须是正在使用的配置端口,默认为 5050。或者,对于使用 Zookeeper 的 Mesos 集群,可以使用 mesos://zk://... 。如果需要以 cluster 模式 --deploy-mode cluster 提交应用程序,HOST 和 PORT 需要配置连接到 MesosClusterDispatcher。 |
yarn |
以 client 或者 cluster 模式连接到 YARN 集群,提交模式取决于参数选项 --deploy-mode 。集群地址将会从环境变量 HADOOP_CONF_DIR 或者 YARN_CONF_DIR 目录下的配置文件中获取。 |
k8s://HOST:PORT |
以 cluster 模式连接到 Kubernetes 集群。目前还不支持模client 式,将会在未来的版本中提供。其中 HOST 和 PORT 参见 Kubernetes API Server。默认情况下开启 TLS,如果需要非安全的连接,可以使用 k8s://http://HOST:PORT 。 |
从文件中加载配置
spark-submit
脚本可以从一个 kv 格式的传递给应用程序的属性文件中加载默认的配置项(Spark configuration values),默认情况下,会读取 Spark 目录下的 conf/spark-defaults.conf
文件,更多详情参见 loading default configurations。
从默认配置文件中加载配置可以避免向 spark-submit
脚本传递一些常规的参数,比如,如果配置文件中配置了 spark.master
参数,就可以省略 spark-submit
脚本中的 --master
选项。一般来说,在 SparkConf
对象中显示定义的配置的优先级最高,其次是通过 spark-submit
脚本传递的配置,最后才是默认配置文件中的配置项。
如果还是不清楚配置项是从哪里获取的,可以为 spark-submit
脚本提供 --verbose
选项来打印细粒度的调试信息。
高级依赖管理
在使用 spark-submit
脚本时,应用程序 Jar 文件以及通过 --jars
选项指定的 Jar 文件都会自动分发到集群中去。--jars
选项指定的 URL 必须以逗号分隔,其中每一项都会被添加到 driver 和 executor 的 classpath 中去。--jars
选项不支持目录展开。
Spark 可以通过下面不同方式的的 URL 模式来指定需要分发的 Jar 文件:
-
file: - 绝对路径,
file:/
URI 由 driver 的 HTTP 文件服务器管理,每个 executor 都从 driver 的 HTTP 服务拉取依赖。 - hdfs:, http:, https:, ftp: - 这些模式将 Jar 文件从相应的 URI 中获取。
-
local: - 以
local:/
为模式的 URI 会被当做在每个 worker 节点上都存在相同的本地文件,这就意味着不会发生网络 IO,要比把一个大文件分发到每个节点,或者通过 NFS,GlusterFS 共享要高效。
注意,Jar 和其他文件会被复制到每个 executor 节点上 SparkContext 的工作目录,有可能会占用很大的空间,需要在适当的时候清理。对于 Yarn 来说,清理操作是自动的,对于 Spark 独立集群管理器,需要通过配置 spark.worker.cleanup.appDataTtl
属性来开启自动清理。
用户还可以通过 --packages
选项提供以逗号分隔的 Maven 坐标来添加其他依赖,所有传递性依赖都可以通过这种方式管理。额外的仓库(或者 SBT resolver)可以通过 --repositories
选项提供,仓库地址以逗号分隔。(注意,有密码保护的仓库可以通过仓库 URI 来提供密匙,例如 https://user:password@host/...
,但是请谨慎使用)。以上选项可以被 pyspark
,spark-shell
和 spark-submit
命令使用来添加依赖。
对于 Python,--py-files
选项可以用来分发 .egg
,.zip
和 .py
依赖库到 executor。
更多信息
一旦部署了自己的应用程序,文档 cluster mode overview 介绍了分布式执行过程中参与的组件,以及如何监控和调试应用程序。