# 集群模式概述

 该文档给出了 Spark 如何在集群上运行、使之更容易来理解所涉及到的组件的简短概述。通过阅读 [应用提交指南](13.md) 来学习在集群上如何启动应用程序。

# 组件

Spark 应用在集群上作为独立的进程组来运行，在你的 `main` 进程中通过 `SparkContext` 来协调（称之为 *driver 进程*）。

具体的说，为了运行在集群上，SparkContext 可以连接至几种类型的  *Cluster Manager*（既可以用 Spark 自己的 `Standlone Cluster Manager`，或者 `Mesos`，也可以使用 `YARN`），它们会分配应用的资源。一旦连接上，Spark 获得集群节点上的 `Executor`，这些进程可以运行计算并且为你的应用存储数据。接下来，它将发送你的应用代码（通过 `JAR` 或者 `Python` 文件定义传递给 `SparkContext`）至 `Executor`。最终，`SparkContext` 将发送 *`Task`* 到 `Executor`  进行运行。

![Spark cluster components](img/1b193ef9791313508d0c806587f136fd.jpg)

这里有几个关于架构需要 *注意* 的地方 :

1. 每个应用获取到它自己的 `Executor` 进程，它们会存活于整个应用生命周期中并且在多个线程中运行 `Task`（任务）。这样做的优点是把应用互相隔离，在调度方面（每个 `Driver` 调度它自己的 `task`）和 `Executor` 方面（来自不同应用的 `task` 运行在不同的 ` JVM ` 中）。然而，这也意味着若是不把数据写到外部存储系统的话，数据就不能够被不同的 `Spark ` 应用（`SparkContext`  的实例）之间共享。
2. `Spark` 是不知道也不需要知道底层的 `Cluster Manager` 到底是什么类型。只要它能够获得 `Executor` 进程，并且它们之间可以通信，那么即便在一个也支持其它应用的 `Cluster Manager`（例如，`Mesos` / `YARN`）上来运行它也是相对简单的。
3. `Driver` 进程必须在自己生命周期内（例如，请参阅 [配置章节](20.md) 网络配置部分 `spark.driver.port` 配置。监听和接受来自它的 Executor 的连接请求。同样的，driver 程序必须可以从 worker 节点上网络寻址（就是网络没问题）。
4. 因为 `driver` 调度了集群上的 `task`（任务），更好的方式应该是在相同的局域网中靠近 `worker` 的节点上运行。如果你不喜欢发送请求到远程的集群，倒不如打开一个 `RPC` 至 `driver` 并让它就近提交操作而不是从很远的 `worker` 节点上运行一个 `driver`。

# Cluster Manager 类型

系统目前支持多种 `cluster manage` 类型:

* [Standalone](15.md) -- 包含在 `Spark` 中使得更容易安装集群的一个简单 `Cluster Manage`
* [Apache Mesos](16.md) -- 一个通用的 `Cluster Manager`，它也可以运行 Hadoop `MapReduce` 和其它服务应用。
* [Hadoop YARN](17.md) -- Hadoop 2 中的 `resource manager`（资源管理器）。
* [Kubernetes](18.md) -- 用于自动化部署、扩展和管理容器化应用程序的开源系统。

存在一个第三方项目(不受Spark项目支持)来添加对[`Nomad`](https://github.com/hashicorp/nomad-spark)作为集群管理器的支持。

# 提交应用程序

使用 **spark-submit** 脚本可以提交应用程序到任何类型的集群。在 [应用提交指南](13.md) 介绍了在不同的集群上如何提交应用程序。

# 监控

每个 `driver` 都有一个 **Web UI**，通常在端口 `4040` 上，可以显示有关正在运行的 `task`，`executor`，和存储使用情况的信息。只需在 Web 浏览器中的`http://<driver-node>:4040` 中访问此 UI。[监控指南](21.md) 中还介绍了其它监控相关工具介绍。

# Job 调度

Spark 即可以在应用间（Cluster Manager 级别），也可以在应用内（如果多个计算发生在相同的 SparkContext 上时）控制资源分配。在 [任务调度概述](23.md) 中更详细地描述了这一点。


# 术语

下表总结了你学习过程中会看到的用于引用集群概念的术语：

<table class="table">
  <thead>
    <tr><th style="width: 130px;">Term</th><th>Meaning</th></tr>
  </thead>
  <tbody>
    <tr>
      <td>Application</td>
      <td>用户构建在 Spark 上的应用程序。由集群上的一个 <em>driver 进程</em> 和多个 <em>executor</em> 组成</td>
    </tr>
    <tr>
      <td>Application jar</td>
      <td>
        一个包含用户 Spark 应用的 Jar。有时候用户会想要去创建一个包含他们应用以及它的依赖的 “uber jar”。用户的 Jar 应该没有包括 Hadoop 或者 Spark 库，然而，它们将会在运行时被添加。 
      </td>
    </tr>
    <tr>
      <td>Driver program</td>
      <td>该进程运行应用的 main() 方法并且创建了 <em>SparkContext。</em> </td>
    </tr>
    <tr>
      <td>Cluster manager</td>
      <td>一个外部的用于获取集群上资源的服务。（例如，Standlone Manager，Mesos，YARN）</td>
    </tr>
    <tr>
      <td>Deploy mode</td>
      <td>根据 driver 程序运行的地方区别。在 “Cluster” 模式中，框架在群集内部启动 driver。在 “Client” 模式中，submitter（提交者）在 Custer 外部启动 driver。</td>
    </tr>
    <tr>
      <td>Worker node</td>
      <td>在集群中可以运行应用程序代码的任何节点。</td>
    </tr>
    <tr>
      <td>Executor</td>
      <td>一个为了在 worker 节点上的应用而启动的进程，它运行 task 并且将数据保持在内存中或者硬盘存储。每个应用有它自己的 Executor。</td>
    </tr>
    <tr>
      <td>Task</td>
      <td>一个将要被发送到 Executor 中的工作单元。</td>
    </tr>
    <tr>
      <td>Job</td>
      <td>一个由多个任务组成的并行计算，并且能从 Spark action 中获取响应（例如 <code>save</code>，<code>collect</code>）; 你将在 driver 的日志中看到这个术语。</td>
    </tr>
    <tr>
      <td>Stage</td>
      <td>每个 Job 被拆分成更小的被称作 <em>stage</em> (阶段）的 <em>task</em>（任务）组，<em>stage</em> 彼此之间是相互依赖的（与 <em>MapReduce</em> 中的 map/reduce <em>stage</em> 相似）。你将在 driver 的日志中看到这个术语。</td>
    </tr>
  </tbody>
</table>

