转载请注明出处,谢谢合作~
Spark 独立集群部署模式
- 安全机制(Security)
- 安装 Spark 独立集群(Installing Spark Standalone to a Cluster)
- 手动启动集群(Starting a Cluster Manually)
- 集群启动脚本(Cluster Launch Scripts)
- 资源分配和配置概览(Resource Allocation and Configuration Overview)
- 应用程序连接到集群(Connecting an Application to the Cluster)
- 启动 Spark 应用程序(Launching Spark Applications)
- 资源调度(Resource Scheduling)
- Executor 调度(Executors Scheduling)
- 监控和日志(Monitoring and Logging)
- 与 Hadoop 协作(Running Alongside Hadoop)
- 网络安全端口配置(Configuring Ports for Network Security)
- 高可用(High Availability)
- 基于 Zookeeper 的后备 master(Standby Masters with ZooKeeper)
- 基于文件系统的单节点故障恢复(Single-Node Recovery with Local File System)
除了采用 Mesos 会偶尔 Yarn 集群管理器,Spark 还提供了一种简单的独立集群部署模式。可以通过手动启动 master 和 worker 节点来启动一个独立集群,或者使用提供的启动脚本(launch scripts)。还可以将这些守护进程在一台机器上启动,用来测试。
安全机制
Spark 中的安全机制默认是关闭的,这意味着在默认情况下你的 Spark 系统很容易收到攻击。请在运行 Spark 之前阅读 Spark Security 文档和本文档中的安全章节。
安装 Spark 独立集群
安装 Spark 独立集群,只需要将编译好的 Spark 版本部署到集群中各个节点就可以了。可以使用预构建的 Spark 版本,或者自行编译(build it yourself)。
手动启动集群
启动 master 节点需要执行:
./sbin/start-master.sh
一旦启动之后,master 会打印一个自己的 spark://HOST:PORT
URL,worker 节点可以使用该 URL 连接到 master,或者将其作为 master
参数传递给 SparkContext
对象。还可以在 master 的界面上找到该 URL,默认界面地址为 http://localhost:8080。
类似的,启动一个或多个 worker 节点,并将其连接到 master 节点,需要执行:
./sbin/start-slave.sh
一旦启动了一个 worker,请查看 master 的界面(默认为 http://localhost:8080),应该可以在列表中看到新加入的 worker 节点,及其 CPU 核数和内存(减去 1 GB,留给操作系统)。
下面的选项可以传递给 master 和 worker 节点:
参数 | 含义 |
---|---|
-h HOST , --host HOST |
监听主机。 |
-i HOST , --ip HOST |
监听主机(已启用,请使用 -h 或者 --host)。 |
-p PORT , --port PORT |
监听端口(master 默认端口为 7077,worker 默认端口随机)。 |
--webui-port PORT |
Web 界面端口(master 默认端口为 8080,worker 默认端口为 8081)。 |
-c CORES , --cores CORES |
该节点上 Spark 应用可以使用的最大核数(默认:所有可用数量),只对 worker 节点有效。 |
-m MEM , --memory MEM |
该节点上 Spark 应用可以使用的最大内存,格式类似 1000M 或者 2G(默认:机器总内存减去 1 GB),只对 worker 节点有效。 |
-d DIR , --work-dir DIR |
缓存以及任务输出日志目录(默认:SPARK_HOME/work ),只对 worker 节点有效。 |
--properties-file FILE |
自定义 Spark 配置文件路径(默认:conf/spark-defaults.conf )。 |
集群启动脚本
使用启动脚本启动 Spark 独立集群,需要在 Spark 根路径下创建一个 conf/slaves
文件,其中包含所有需要启动 worker 节点的主机名,一个一行。如果 conf/slaves
文件不存在,启动脚本会默认在本机(localhost
)启动一个 worker,适用于测试环境。注意,master 节点通过 ssh 访问每个 worker 节点。默认情况下,ssh 并行执行并且需要配置免密登录(通过私匙)。如果没有配置免密登录,可以设置环境变量 SPARK_SSH_FOREGROUND
,顺序提供每个 worker 节点的密码。
一旦准好好配置文件,就可以使用下面的的 shell 脚本来启动和停止集群,和 Hadoop 集群的部署脚本类似,在 SPARK_HOME/sbin
目录下:
-
sbin/start-master.sh
- 在脚本所在的节点上启动 master 实例。 -
sbin/start-slaves.sh
- 在conf/slaves
文件中定义的所有节点上启动 worker 实例。 -
sbin/start-slave.sh
- 在脚本所在的节点上启动 worker 实例。 -
sbin/start-all.sh
- 按上面的方式启动一个 master 实例和一些 worker 实例。 -
sbin/stop-master.sh
- 停止由sbin/start-master.sh
脚本启动的 master 实例。 -
sbin/stop-slave.sh
- 在脚本所在的节点上停止所有 worker 实例。 -
sbin/stop-slaves.sh
- 在conf/slaves
文件中定义的所有节点上停止 worker 实例。 -
sbin/stop-all.sh
- 按上面的方式停止一个 master 实例和一些 worker 实例。
注意,上述脚本都需要在 Spark master 节点上执行,而不是本地机器。
还可以通过 conf/spark-env.sh
文件以配置环境变量的方式配置集群,可以参考 conf/spark-env.sh.template
文件进行配置(通常都复制该文件),之后将其拷贝到所有的 worker 节点上使之生效。这些环境变量如下:
环境变量 | 含义 |
---|---|
SPARK_MASTER_HOST |
Master 节点监听地址。 |
SPARK_MASTER_PORT |
Master 节点监听端口(默认:7077). |
SPARK_MASTER_WEBUI_PORT |
Master 节点 Web 界面监听端口(默认:8080)。 |
SPARK_MASTER_OPTS |
作用于 master 的配置项,格式为 -Dx=y (默认为空),可选项参见下面的列表。 |
SPARK_LOCAL_DIRS |
Spark 中的临时目录,包括 map 输出文件和溢写到硬盘的 RDD。该目录应该是一个快速的本地硬盘,也可以配置为以逗号分隔的术语多个硬盘的目录。 |
SPARK_WORKER_CORES |
该节点上 Spark 应用程序可以使用的总核数(默认:所有可用数量)。 |
SPARK_WORKER_MEMORY |
该节点上 Spark 应用可以使用的最大内存,例如 1000m,2g(默认:机器总内存减去 1 GB);单个 Spark 应用程序的内存通过参数 spark.executor.memory 配置。 |
SPARK_WORKER_PORT |
Master 节点监听端口(默认:随机)。 |
SPARK_WORKER_WEBUI_PORT |
Worker节点 Web 界面监听端口(默认:8081)。 |
SPARK_WORKER_DIR |
应用程序运行时的缓存和日志目录(默认:SPARK_HOME/work )。 |
SPARK_WORKER_OPTS |
作用于 worker 的配置项,格式为 -Dx=y (默认为空),可选项参见下面的列表。 |
SPARK_DAEMON_MEMORY |
为 master 和 worker 守护进程分配的内存(默认:1g)。 |
SPARK_DAEMON_JAVA_OPTS |
作用于 master 和 worker 守护进程的 JVM 选项,格式为 -Dx=y (默认为空)。 |
SPARK_DAEMON_CLASSPATH |
Spark master 和 worker 守护进程的 classpath(默认为空)。 |
SPARK_PUBLIC_DNS |
Spark master 和 workers 所用的公用 DNS 服务地址(默认为空)。 |
注意:启动脚本目前不支持 Windows,如果要在 Windows 环境下启动 Spark 独立集群,请手动启动 master 和 worker 节点。
环境变量 SPARK_MASTER_OPTS
支持下面的系统属性:
属性名称 | 默认值 | 含义 | 起始版本 |
---|---|---|---|
spark.deploy.retainedApplications |
200 | 展示运行完成的应用程序的最大数量。在页面上更早的应用程序数据会被丢弃。 | 0.8.0 |
spark.deploy.retainedDrivers |
200 | 展示运行完成的 driver 的最大数量。在页面上更早的 driver 数据会被丢弃。 | 1.1.0 |
spark.deploy.spreadOut |
true | 独立集群管理器是否应该将应用程序分散到集群的各个节点上,或是尽量将它们安排在少数几个节点上。分散的方式更有利于 HDFS 数据的本地性,而收紧的方式对于计算密集型的场景会更高效。 | 0.6.1 |
spark.deploy.defaultCores |
(infinite) | 如果应用程序没有设置参数 spark.cores.max ,为其分配的默认核数。如果没有设置该参数,应用程序会获取集群中所有可用的核数,除非配置参数 spark.cores.max 。将该参数设置为一个较小值可以避免用户抢夺集群资源。 |
0.9.0 |
spark.deploy.maxExecutorRetries |
10 | Executor 在失败时的最大重试次数,之后集群管理器会移除对应失败的应用程序。当一个应用程序还有在运行的 executor 时是不会被移除的。如果一个应用程序连续发生了 spark.deploy.maxExecutorRetries 次失败,没有 executor 在这些失败之后还继续运行,应用程序也不再有还在运行的 executor,那么集群管理器会移除该应用程序并标记其为失败状态。禁用这种自动的移除机制,需要将参数 spark.deploy.maxExecutorRetries 设置为 -1 。 |
1.6.3 |
spark.worker.timeout |
60 | 在多少秒没有收到 worker 发送的心跳信息之后,认为该 worker 丢失。 | 0.6.2 |
spark.worker.resource.{resourceName}.amount |
(none) | Worker 使用的特定资源的数量。 | 3.0.0 |
spark.worker.resource.{resourceName}.discoveryScript |
(none) | 资源发现脚本路径,用来在 worker 启动时发现可用的集群资源,脚本的输出格式应该符合 ResourceInformation 类。 |
3.0.0 |
spark.worker.resourcesFile |
(none) | 资源文件路径,用来在 worker 启动时查找不同类型的集群资源。文件内容格式为 [{"id":{"componentName": "spark.worker","resourceName":"gpu"},"addresses":["0","1","2"]}] 。如果文件中没有定义某一类型的资源,就会使用资源发现脚本来获取。如果资源发现脚本也没有找到资源,worker 会启动失败。 |
3.0.0 |
环境变量 SPARK_WORKER_OPTS
支持下面的系统属性:
属性名称 | 默认值 | 含义 | 起始版本 |
---|---|---|---|
spark.worker.cleanup.enabled |
false | 是否开启定期清理 worker/application 目录。注意,该配置只在独立集群部署模式生效,因为 Yarn 的工作机制有所不同。只有已停止的应用的目录会被清理。在参数 spark.shuffle.service.db.enabled 设置为 true 时,应该开启该选项。 |
1.0.0 |
spark.worker.cleanup.interval |
1800 (30 minutes) | 控制 worker 自动清理已完成应用程序工作目录的时间间隔,单位为秒。 | 1.0.0 |
spark.worker.cleanup.appDataTtl |
604800 (7 days, 7 * 24 * 3600) | 每个 worker 保留应用程序工作目录的时限,单位为秒。这是一个 TTL(Time To Live)配置,应该根据可用的磁盘空间进行设置。应用程序日志和 Jar 文件会下载到每个应用程序的工作目录。随着时间的迁移,工作目录可能会快速吞噬磁盘空间,尤其是在频繁运行任务的时候。 | 1.0.0 |
spark.shuffle.service.db.enabled |
true | 将 External Shuffle 服务的状态写入到磁盘,在External Shuffle 服务重启时,这些状态会被自动加载到当前的 executor 中。该参数只在独立集群部署模式下起作用(Yarn 总是开启该功能)。应该同时开启 spark.worker.cleanup.enabled 参数,以保证状态会被最终清理。该配置在将来的版本中可能会被移除。 |
3.0.0 |
spark.storage.cleanupFilesAfterExecutorExit |
true | 在 executor 退出后清理非 shuffle 文件(临时 shuffle 数据块,RDD/广播变量缓存,溢写文件等等)。注意,该配置与配置项 spark.worker.cleanup.enabled 没有重叠,该配置清理退出的 executor 中的非 shuffle 文件,而配置项 spark.worker.cleanup.enabled 清理停止的和超时的应用程序的工作目录中所有的文件和子目录。该配置只对独立集群部署模式生效,对其他集群管理器的支持将会在未来版本中添加。 |
2.4.0 |
spark.worker.ui.compressedLogFileLengthCacheSize |
100 | 对于压缩的日志文件,未压缩的文件大小只能通过未压缩的文件进行计算。Spark 会缓存已压缩日志文件的未压缩大小,该配置控制缓存的大小。 | 2.0.2 |
资源分配和配置概览
请确保已经阅读了配置文档 configuration page 中的「自定义资源调度和配置概览」章节(Custom Resource Scheduling and Configuration Overview)。本章节只讨论有关 Spark 独立集群相关的资源调度。
Spark 独立集群的资源分配分为两部分,一部分是配置 worker 使用的资源,另一部分是某个应用程序的资源分配。
用户必须为 worker 配置一个资源集,从而使 worker 可以将其分配给不同的 executor。参数 spark.worker.resource.{resourceName}.amount
用来控制分配给 worker 的不同资源的数量。用户必须指定 spark.worker.resourcesFile
或者 spark.worker.resource.{resourceName}.discoveryScript
来指定 worker 如何发现所分配的资源。请参考上面的描述来判断你的场景适合哪种方式。
另一部分是在 Spark 独立集群上运行一个应用程序,对于标准的 Spark 资源配置唯一特殊的场景就是以 client
模式运行应用程序。对于以 client
模式运行的 driver,用户可以通过参数 spark.driver.resourcesfile
或者 spark.driver.resource.{resourceName}.discoveryScript
来指定分配的资源。如果一个 driver 和其他的 driver 运行在同一个节点上,需要保证资源文件或者资源发现脚本返回的资源之间不会相互冲突。
注意,用户在提交应用程序时不需要指定资源发现脚本,因为 worker 会根据分配给 executor 的资源来启动 executor。
应用程序连接到集群
在 Spark 独立集群上运行应用程序,只需要将 master 的 spark://IP:PORT
URL 传递给 SparkContext 对象的构造器(SparkContext
constructor)。
在 Spark 独立集群上交互式运行 Spark shell,请执行下面的命令:
./bin/spark-shell --master spark://IP:PORT
还可以通过参数 --total-executor-cores
控制 spark shell 在集群中可用的核数。
启动 Spark 应用程序
通过 spark-submit
script 脚本提交 Spark 应用程序到集群的最直接的一种方式。对于 Spark 独立集群,目前支持两种提交模式。在 client
模式下,driver 作为客户端在提交应用程序的进程中启动;而在 cluster
模式下,driver 在集群中某个 worker 节点上启动,客户端进程会在提交程序到集群中,完成了自己的职责之后推出,不必等待应用程序执行结束。
如果通过 spark-submit
脚本提交应用程序,那么应用程序 Jar 文件会被自动分发到所有的 worker 节点。对于其他的依赖,应该通过 --jars
参数以逗号分隔的格式指定(例如,--jars jar1,jar2
)。对于应用程序配置或者执行环境,参见 Spark Configuration。
另外,独立集群的 cluster
模式支持在应用程序异常退出的时候进行重启,需要在提交应用程序时将参数 --supervise
传递给 spark-submit
脚本。之后,如果想杀掉一个一直失败的应用程序,需要:
./bin/spark-class org.apache.spark.deploy.Client kill
可以在独立集群的 master 界面 http://
上找到 driver ID。
资源调度
独立集群的 cluster
模式目前只支持简单的 FIFO 调度器。然而,为了让多个用户可以同时提交任务,可以控制一个应用可以使用的最大资源。默认情况下,会将集群中所有的核数都分配给一个应用程序,只适用于同时只运行一个应用程序的场景。可以通过 SparkConf 对象中的 spark.cores.max
参数来指定应用程序可用的最大核数。例如:
val conf = new SparkConf()
.setMaster(...)
.setAppName(...)
.set("spark.cores.max", "10")
val sc = new SparkContext(conf)
此外,还可以在 master 进程中配置参数 spark.deploy.defaultCores
改变应用程序默认使用的核数,而不用再设置参数 spark.cores.max
。需要将下面的变量添加到 conf/spark-env.sh
:
export SPARK_MASTER_OPTS="-Dspark.deploy.defaultCores="
这种方式适用于多用户共享一个集群,但是用户可能没有对每一个应用程序都配置最大使用核数。
Executor 调度
每个 executor 可用的核数是可以配置的。当参数 spark.executor.cores
被显示指定时,属于一个应用程序的多个 executor 可能会被分配到一个 worker 上,如果该 worker 的资源足够的话。否则,默认情况下每个 executor 会将一个 worker 上的核数用尽,此时在一个调度周期内,一个应用程序只会有一个 executor 分配到一个 worker 上。
监控和日志
Spark 独立集群部署模式提供了基于 web 的用户接口来监控集群。Master 和每个 worker 都有自己的 web 界面,展示了集群和任务的统计信息。默认情况下,可以通过 8080 端口访问 master 的 web 界面。该端口可能会被配置文件或者命令行参数改变。
另外,每个应用的详细日志输出也被写入到每个 worker 节点上的工作目录(默认为 SPARK_HOME/work
),对于每个应用程序可以看到两个日志文件,stdout
和 stderr
,其中包含了所有输出到控制台的信息。
与 Hadoop 协作
可以让 Spark 独立集群启动在 Hadoop 集群相同的节点上。如果需要从 Spark 中访问 Hadoop 数据,只需要使用 hdfs://
URL 即可(通常是 hdfs://
,可以在 Hadoop Namenode 的界面上找到正确的 URL)。也可为 Spark 启动一个单独的集群,通过网络访问 HDFS 数据;这种方式要比直接访问本地磁盘数据慢一些,但是如果在同一个网络平面内也不是什么大问题(例如,将一些 Spark 机器部署在 Hadoop 集群相同的机架上)。
网络安全端口配置
一般来说,一个 Spark 集群及其相关服务不会部署在公网环境下。它们应该是私有服务,只允许被部署该集群的组织在私网内访问。对于 Spark 使用的主机和端口的访问应该被限制在需要使用这些服务的机器中。
这一点对于独立集群资源管理器尤其重要,因为该模式不支持像其他资源管理器那样细粒度的访问权限控制。
对于需要配置的端口的完整列表,参见 security page。
高可用
默认情况下,独立集群部署模式对于 worker 的失败是弹性容错的(Spark 会将故障 worker 上的 executor 转移到其他正常的 worker 继续运行)。然而,调度器通过 master 来做调度决定,这有可能造成单点故障问题(默认情况下):如果 master 宕机,就不会在创建新的应用程序了。为了规避这种风险,有以下两种高可用解决方案。
基于 Zookeeper 的后备 master
概述
使用 Zookeeper 支撑 leader 选举和一些状态存储,可以启动多个 master 连接到同一个 Zookeeper 集群。其中一个 master 会被选举为「leader」,其他的会保持在后备模式。如果当前的 leader 发生故障,另一个 master 会被选举出来,恢复之前的 master 的状态,之后重新调度任务。完整的恢复过程(从第一个 leader 出现故障开始)可能会花费 1 到 2 分钟。注意,这个延迟只影响调度新的应用程序——已经在运行的应用程序在 master 的失败迁移过程中是不受影响的。
关于 Zookeeper 的更多详情参见 here。
配置
启用这种恢复模式,需要在 spark-env.sh
文件中设置环境变量 SPARK_DAEMON_JAVA_OPTS
的值中包含 spark.deploy.recoveryMode
和相应的 spark.deploy.zookeeper.*
参数。更多详情参见 configuration doc。
可能的陷阱:如果启动了多个 master,但是没有正确配置它们使用 Zookeeper,那么这些 master 不会发现彼此,都会认为自己是 leader,这样集群的健康状态将不会得到保证(所有的 master 都会独立调度任务)。
详情
如果已经存在一个 Zookeeper 集群,启用高可用就很简单。只需要在不同节点上启动 master 进程时使用相同的 Zookeeper 配置(Zookeeper URL 和路径)即可。这些 master 可以在任何时候被添加和移除。
对于调度新的应用程序或者添加 worker 到集群中,它们需要指导当前 leader 的 IP 地址,可以简单的将所有的 master 地址以逗号分隔取代之前的单一的地址。例如,可以让 SparkContext 对象指向 spark://host1:port1,host2:port2
,这样会让 SparkContext 对象尝试注册到两个 master 上——如果 host1
宕机了,配置依然是正确的,因为可以找到一个新的 leader,host2
。
在「注册到一个 master 上」和正常的操作之间有一个重要的区别,在程序启动时,一个应用程序或者 worker 需要找到并注册到当前的领导者 master 上,一旦注册成功,就说明该应用程序或者 worker 已经「在系统中」了(即,存储到了 Zookeeper)。如果发生失败迁移,新的 leader 会联系之前注册过的应用程序和 worker,通知它们改变 leader,所以它们在启动的时候不需要知道新的 master 的存在。
因此,新的 master 可以在任何时候启动,需要担心的仅仅是新的应用程序和 worker 在新 master 成为 leader 时能够找到该 master 并注册自己。一旦注册成功,就会被妥善处置。
基于文件系统的单节点故障恢复
概述
Zookeeper 是最好的高可用方案,可以在生产环境中适用,但是如果只需要在 master 宕机后重启该 master,FILESYSTEM 模式就可以实现。在应用程序和 worker 注册时,会在指定的目录中写入足够的状态数据,使之能够在重启 master 进程时恢复。
配置
启用这种恢复模式,需要在 spark-env.sh
文件中设置环境变量 SPARK_DAEMON_JAVA_OPTS
:
系统属性 | 含义 | 起始版本 |
---|---|---|
spark.deploy.recoveryMode |
设置为 FILESYSTEM 来开启单点恢复(默认:NONE)。 | 0.8.1 |
spark.deploy.recoveryDirectory |
Spark 存储恢复状态数据的目录,需要 master 有读写权限。 | 0.8.1 |
详情
- 这种方案可以和一个像 monit 这样的监控/管理进程一起使用,或者仅仅是在重启时开启手动恢复。
- 尽管文件系统恢复看起来比不做任何恢复要好得多,这种模式只是在开发或者实验时的次优选择。尤其是,通过
stop-master.sh
脚本杀掉一个 master 时,并不会清理该目录,所以每次启动一个新的 master,就会进入恢复模式。这样而可能导致启动时间增加到 1 分钟左右,因为需要等待之前注册过的应用程序和 worker/client 超时。 - 虽然没有得到官方支持,还是可以将一个 NFS 目录作为恢复目录。如果之前的 master 发生故障,可以在其他节点上启动一个 master,并正确的恢复之前注册过的应用程序和 worker(等同于 Zookeeper 恢复模式)。然而, 之后的应用程序必须能够找到新的 master 来注册自己。