一、简介
Spark 的一大好处就是可以通过增加机器数量并使用集群模式运行,来扩展程序的计算能力。好在编写用于在集群上并行执行的 Spark 应用所使用的 API 跟本地单机模式下的完全一样。也就是说,你可以在小数据集上利用本地模式快速开发并验证你的应用,然后无需修改代码就可以在大规模集群上运行。
首先介绍分布式 Spark 应用的运行环境架构,然后讨论在集群上运行 Spark 应用时的一些配置项。Spark 可以在各种各样的集群管理器(Hadoop YARN、Apache Mesos,还有Spark 自带的独立集群管理器)上运行,所以 Spark 应用既能够适应专用集群,又能用于共享的云计算环境。
二、Spark运行时架构
在分布式环境下,Spark 集群采用的是主 / 从结构。在一个 Spark 集群中,有一个节点负责中央协调,调度各个分布式工作节点。这个中央协调节点被称为驱动器(Driver)节点,与之对应的工作节点被称为执行器(executor)节点。驱动器节点可以和大量的执行器节点进行通信,它们也都作为独立的 Java 进程运行。驱动器节点和所有的执行器节点一起被称为一个 Spark 应用(application)。
Spark 应用通过一个叫作集群管理器(Cluster Manager)的外部服务在集群中的机器上启动。Spark 自带的集群管理器被称为独立集群管理器。Spark 也能运行在 Hadoop YARN 和Apache Mesos 这两大开源集群管理器上。
1、驱动器节点
Spark 驱动器是执行你的程序中的 main() 方法的进程。它执行用户编写的用来创建SparkContext、创建 RDD,以及进行 RDD 的转化操作和行动操作的代码。其实,当你启动 Spark shell 时,你就启动了一个 Spark 驱动器程序(相信你还记得,Spark shell 总是会预先加载一个叫作 sc 的 SparkContext 对象)。驱动器程序一旦终止,Spark 应用也就结束了。
驱动器程序在 Spark 应用中有下述两个职责。
• 把用户程序转为任务
Spark 驱动器程序负责把用户程序转为多个物理执行的单元,这些单元也被称为任务(task)。从上层来看,所有的 Spark 程序都遵循同样的结构:程序从输入数据创建一系列 RDD,再使用转化操作派生出新的 RDD,最后使用行动操作收集或存储结果 RDD中的数据。
Spark 程序其实是隐式地创建出了一个由操作组成的逻辑上的有向无环图(Directed Acyclic Graph,简称 DAG)。当驱动器程序运行时,它会把这个逻辑图转为物理执行计划。
Spark 会对逻辑执行计划作一些优化,比如将连续的映射转为流水线化执行,将多个操作合并到一个步骤中等。这样 Spark 就把逻辑计划转为一系列步骤(stage)。而每个步骤又由多个任务组成。这些任务会被打包并送到集群中。任务是 Spark 中最小的工作单元,用户程序通常要启动成百上千的独立任务。
• 为执行器节点调度任务
有了物理执行计划之后,Spark 驱动器程序必须在各执行器进程间协调任务的调度。执行器进程启动后,会向驱动器进程注册自己。因此,驱动器进程始终对应用中所有的执行器节点有完整的记录。每个执行器节点代表一个能够处理任务和存储 RDD 数据的进程。
Spark 驱动器程序会根据当前的执行器节点集合,尝试把所有任务基于数据所在位置分配给合适的执行器进程。当任务执行时,执行器进程会把缓存数据存储起来,而驱动器进程同样会跟踪这些缓存数据的位置,并且利用这些位置信息来调度以后的任务,以尽量减少数据的网络传输。
驱动器程序会将一些 Spark 应用的运行时的信息通过网页界面呈现出来,默认在端口4040 上。比如,在本地模式下,访问 http://localhost:4040 就可以看到这个网页了。
2、执行器节点
Spark 执行器节点是一种工作进程,负责在 Spark 作业中运行任务,任务间相互独立。Spark 应用启动时,执行器节点就被同时启动,并且始终伴随着整个 Spark 应用的生命周期而存在。如果有执行器节点发生了异常或崩溃,Spark 应用也可以继续执行。执行器进
程有两大作用:第一,它们负责运行组成 Spark 应用的任务,并将结果返回给驱动器进程;第二,它们通过自身的块管理器(Block Manager)为用户程序中要求缓存的 RDD 提供内存式存储。RDD 是直接缓存在执行器进程内的,因此任务可以在运行时充分利用缓存数据加速运算。
在本地模式下,Spark 驱动器程序和各执行器程序在同一个 Java 进程中运行。这是一个特例;执行器程序通常都运行在专用的进程中。
3、启动一个程序
不论你使用的是哪一种集群管理器,你都可以使用 Spark 提供的统一脚本 spark-submit 将你的应用提交到那种集群管理器上。通过不同的配置选项, spark-submit 可以连接到相应的集群管理器上,并控制应用所使用的资源数量。在使用某些特定集群管理器时, spark-submit 也可以将驱动器节点运行在集群内部(比如一个 YARN 的工作节点)。但对于其他的集群管理器,驱动器节点只能被运行在本地机器上。
4、小结
在集群上运行 Spark 应用的详细过程
(1) 用户通过 spark-submit 脚本提交应用。
(2) spark-submit 脚本启动驱动器程序,调用用户定义的 main() 方法。
(3) 驱动器程序与集群管理器通信,申请资源以启动执行器节点。
(4) 集群管理器为驱动器程序启动执行器节点。
(5) 驱动器进程执行用户应用中的操作。根据程序中所定义的对 RDD 的转化操作和行动操作,驱动器节点把工作以任务的形式发送到执行器进程。
(6) 任务在执行器程序中进行计算并保存结果。
(7) 如果驱动器程序的 main() 方法退出,或者调用了 SparkContext.stop() ,驱动器程序会终止执行器进程,并且通过集群管理器释放资源。
三、使用spark-submit部署应用
Spark 为各种集群管理器提供了统一的工具来提交作业,这个工具是 spark-submit 。在调用 spark-submit 时除了脚本或 JAR 包的名字之外没有别的参数,那么这个 Spark程序只会在本地执行。当我们希望将应用提交到 Spark 独立集群上的时候,除了脚本或 JAR 包的名字之外还必须有别的参数。例如:
bin/spark-submit --master spark://host:7077 --executor-memory 10g my_script.py
--master 标记指定要连接的集群 URL;下表给出了spark-submit 的 --master 标记可以接收的值
除了集群 URL, spark-submit 还提供了各种选项,可以让你控制应用每次运行的各项细节。这些选项主要分为两类。第一类是调度信息,比如你希望为作业申请的资源量。第二类是应用的运行时依赖,比如需要部署到所有工作节点上的库和文件。下面列出 spark-submit 的一些常见标记。
还可以运行 spark-submit --help 列出所有可以接收的标记。
四、集群管理器
Spark 可以运行在各种集群管理器上,并通过集群管理器访问集群中的机器。如果你只想在一堆机器上运行 Spark,那么自带的独立模式是部署该集群最简单的方法。然而,如果你有一个需要与别的分布式应用共享的集群(比如既可以运行 Spark 作业又可以运行Hadoop MapReduce 作业),Spark 也可以运行在两个广泛使用的集群管理器——HadoopYARN 与 Apache Mesos 上面。最后,在把 Spark 部署到 Amazon EC2 上时,Spark 有个自带的脚本可以启动独立模式集群以及各种相关服务。
Spark 所支持的各种集群管理器为我们提供了部署应用的多种选择。如果你需要从零开始部署,正在权衡各种集群管理器,我们推荐如下一些准则。
• 如果是从零开始,可以先选择独立集群管理器。独立模式安装起来最简单,而且如果你只是使用 Spark 的话,独立集群管理器提供与其他集群管理器完全一样的全部功能。
• 如果你要在使用 Spark 的同时使用其他应用,或者是要用到更丰富的资源调度功能(例如队列),那么 YARN 和 Mesos 都能满足你的需求。而在这两者中,对于大多数Hadoop 发行版来说,一般 YARN 已经预装好了。
• Mesos 相对于 YARN 和独立模式的一大优点在于其细粒度共享的选项,该选项可以将类似 Spark shell 这样的交互式应用中的不同命令分配到不同的 CPU 上。因此这对于多用户同时运行交互式 shell 的用例更有用处。
• 在任何时候,最好把 Spark 运行在运行 HDFS 的节点上,这样能快速访问存储。你可以自行在同样的节点上安装 Mesos 或独立集群管理器。如果使用 YARN 的话,大多数发行版已经把 YARN 和 HDFS 安装在了一起。
这篇博文主要来自《Spark快速大数据分析》这本书里面的第七章,内容有删减。