提交 e0a9caa2 编写于 作者: W wizardforcel

init

上级
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# dotenv
.env
# virtualenv
.venv
venv/
ENV/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.DS_Store
# gitbook
_book
# node.js
node_modules
# windows
Thumbs.db
# word
~$*.docx
~$*.doc
# custom
docs/README.md
language: python
python: 3.6
install:
- ':'
script:
- ':'
after_script:
- git config user.name ${GH_UN}
- git config user.email ${GH_EMAIL}
- git push "https://${GH_TOKEN}@github.com/${GH_USER}/${GH_REPO}.git" v2.2.0-md:${GH_BRANCH} -f
env:
global:
- GH_UN=jiangzhonglian
- GH_EMAIL=jiang-s@163.com
- GH_USER=apachecn
- GH_REPO=spark-doc-zh
- GH_BRANCH=gh-pages
\ No newline at end of file
spark.apachecn.org
\ No newline at end of file
# 贡献指南
## 参与翻译 & 发现错误
1. 在 github 上 fork 该 repository.
2. 翻译 doc/zh 下面的 md 文件即可, 例如, index.md.
3. 然后, 在你的 github 发起 New pull request 请求.
4. 工具使用, 可参考下面的内容.
## 工具使用(针对新手)
工欲善其事, 必先利其器 ...
工具随意, 能达到效果就好.
我这里使用的是 `VSCode` 编辑器.
简易的使用指南请参阅: [VSCode Windows 平台入门使用指南](help/vscode-windows-usage.md), 介绍了 `VSCode``github` 一起搭配的简易使用的方法.
如果要将 VSCode 的 Markdown 预览风格切换为 github 的风格,请参阅: [VSCode 修改 markdown 的预览风格为 github 的风格](help/vscode-markdown-preview-github-style.md).
## 角色分配
目前有如下可分配的角色:
* 翻译: 负责文章内容的翻译.
* 校验: 负责文章内容的校验, 比如格式, 正确度之类的.
* 负责人: 负责整个 Projcet, 不至于让该 Project 成为垃圾项目, 需要在 Spark 方面经验稍微丰富点.
有兴趣参与的朋友, 可以看看最后的联系方式.
# Apache Spark 官方文档中文版
![](docs/img/spark-logo-hd.png)
Apache Spark? 是一个快速的, 用于海量数据处理的通用引擎.
## 维护地址
+ [Github](https://github.com/apachecn/spark-doc-zh/)
+ [在线阅读](http://spark.apachecn.org)
## 历史版本
+ [Apache Spark 2.0.2 官方文档中文版](http://cwiki.apachecn.org/pages/viewpage.action?pageId=2883613)
+ [中文文档 EPUB 格式](https://github.com/apachecn/spark-doc-zh/raw/dl/Spark%202.0.2%20%E4%B8%AD%E6%96%87%E6%96%87%E6%A1%A3.epub)
## 贡献指南
[请见这里](CONTRIBUTING.md)
## 负责人
* [@wangyangting](https://github.com/wangyangting)(那伊抹微笑)
## 贡献者
贡献者可自行编辑如下内容.
### 2.2.0
* [@wangyangting](https://github.com/wangyangting)(那伊抹微笑)
* [@jiangzhonglian](https://github.com/jiangzhonglian)(片刻)
* [@chenyyx](https://github.com/chenyyx)(Joy yx)
* [@XiaoLiz](https://github.com/XiaoLiz)(VoLi)
* [@ruilintian](https://github.com/ruilintian)(ruilintian)
* [@huangtianan](https://github.com/huangtianan)(huangtianan)
* [@kris37](https://github.com/kris37)(kris37)
* [@sehriff](https://github.com/sehriff)(sehriff)
* [@windyqinchaofeng](https://github.com/windyqinchaofeng)(qinchaofeng)
* [@stealthsMrs](https://github.com/stealthsMrs)(stealthsMrs)
### 2.0.2
请参阅: [http://cwiki.apachecn.org/pages/viewpage.action?pageId=2887089](http://cwiki.apachecn.org/pages/viewpage.action?pageId=2887089)
## 联系方式
有任何建议反馈, 或想参与文档翻译, 麻烦联系下面的企鹅:
* 企鹅: 1042658081
+ [Spark 概述](docs/1.md)
+ [编程指南](docs/2.md)
+ [快速入门](docs/3.md)
+ [Spark 编程指南](docs/4.md)
+ [构建在 Spark 之上的模块](docs/5.md)
+ [Spark Streaming 编程指南](docs/6.md)
+ [Spark SQL, DataFrames and Datasets Guide](docs/7.md)
+ [MLlib](docs/8.md)
+ [GraphX Programming Guide](docs/9.md)
+ [API 文档](docs/10.md)
+ [部署指南](docs/11.md)
+ [集群模式概述](docs/12.md)
+ [Submitting Applications](docs/13.md)
+ [部署模式](docs/14.md)
+ [Spark Standalone Mode](docs/15.md)
+ [在 Mesos 上运行 Spark](docs/16.md)
+ [Running Spark on YARN](docs/17.md)
+ [其它](docs/18.md)
+ [更多](docs/19.md)
+ [Spark 配置](docs/20.md)
+ [Monitoring and Instrumentation](docs/21.md)
+ [Tuning Spark](docs/22.md)
+ [作业调度](docs/23.md)
+ [Spark 安全](docs/24.md)
+ [硬件配置](docs/25.md)
+ [Accessing OpenStack Swift from Spark](docs/26.md)
+ [构建 Spark](docs/27.md)
+ [其它](docs/28.md)
+ [外部资源](docs/29.md)
+ [翻译进度](docs/30.md)
# Spark 概述
Apache Spark 是一个快速的, 多用途的集群计算系统。 它提供了 Java, Scala, Python 和 R 的高级 API,以及一个支持通用的执行图计算的优化过的引擎. 它还支持一组丰富的高级工具, 包括使用 SQL 处理结构化数据处理的 [Spark SQL](sql-programming-guide.html), 用于机器学习的 [MLlib](ml-guide.html), 用于图计算的 [GraphX](graphx-programming-guide.html), 以及 [Spark Streaming](streaming-programming-guide.html)
# 下载
从该项目官网的 [下载页面](http://spark.apache.org/downloads.html) 获取 Spark. 该文档用于 Spark 2.2.0 版本. Spark可以通过Hadoop client库使用HDFS和YARN.下载一个预编译主流Hadoop版本比较麻烦. 用户可以下载一个编译好的Hadoop版本, 并且可以 通过[设置 Spark 的 classpath](hadoop-provided.html) 来与任何的 Hadoop 版本一起运行 Spark. Scala 和 Java 用户可以在他们的工程中通过Maven的方式引入 Spark, 并且在将来 Python 用户也可以从 PyPI 中安装 Spark。
如果您希望从源码中编译一个Spark, 请访问 [编译 Spark](building-spark.html).
Spark可以在windows和unix类似的系统(例如, Linux, Mac OS)上运行。它可以很容易的在一台本地机器上运行 -你只需要安装一个JAVA环境并配置PATH环境变量,或者让JAVA_HOME指向你的JAVA安装路径
Spark 可运行在 Java 8+, Python 2.7+/3.4+ 和 R 3.1+ 的环境上。针对 Scala API, Spark 2.2.0 使用了 Scala 2.11\. 您将需要去使用一个可兼容的 Scala 版本 (2.11.x).
请注意, 从 Spark 2.2.0 起, 对 Java 7, Python 2.6 和旧的 Hadoop 2.6.5 之前版本的支持均已被删除.
请注意, Scala 2.10 的支持已经不再适用于 Spark 2.1.0, 可能会在 Spark 2.3.0 中删除。
# 运行示例和 Shell
Spark 自带了几个示例程序. Scala, Java, Python 和 R 示例在 `examples/src/main` 目录中. 要运行 Java 或 Scala 中的某个示例程序, 在最顶层的 Spark 目录中使用 `bin/run-example <class> [params]` 命令即可.(这个命令底层调用了 [`spark-submit` 脚本](submitting-applications.html)去加载应用程序)。例如,
```
./bin/run-example SparkPi 10
```
您也可以通过一个改进版的 Scala shell 来运行交互式的 Spark。这是一个来学习该框架比较好的方式。
```
./bin/spark-shell --master local[2]
```
`--master`选项可以指定为 [针对分布式集群的 master URL](submitting-applications.html#master-urls), 或者 以`local`模式 使用 1 个线程在本地运行, `local[N]` 会使用 N 个线程在本地运行.你应该先使用local模式进行测试. 可以通过–help指令来获取spark-shell的所有配置项. Spark 同样支持 Python API。在 Python interpreter(解释器)中运行交互式的 Spark, 请使用 `bin/pyspark`:
```
./bin/pyspark --master local[2]
```
Python 中也提供了应用示例。例如,
```
./bin/spark-submit examples/src/main/python/pi.py 10
```
从 1.4 开始(仅包含了 DataFrames APIs)Spark 也提供了一个用于实验性的 [R API](sparkr.html)。 为了在 R interpreter(解释器)中运行交互式的 Spark, 请执行 `bin/sparkR`:
```
./bin/sparkR --master local[2]
```
R 中也提供了应用示例。例如,
```
./bin/spark-submit examples/src/main/r/dataframe.R
```
# 在集群上运行
该 Spark [集群模式概述](cluster-overview.html) 说明了在集群上运行的主要的概念。 Spark 既可以独立运行, 也可以在一些现有的 Cluster Manager(集群管理器)上运行。它当前提供了几种用于部署的选项:
* [Standalone Deploy Mode](spark-standalone.html): 在私有集群上部署 Spark 最简单的方式
* [Apache Mesos](running-on-mesos.html)
* [Hadoop YARN](running-on-yarn.html)
# API 文档
* [Spark Scala API (Scaladoc)](http://spark.apache.org/docs/2.2.0/api/scala/index.html#org.apache.spark.package)
* [Spark Java API (Javadoc)](http://spark.apache.org/docs/2.2.0/api/java/index.html)
* [Spark Python API (Sphinx)](http://spark.apache.org/docs/2.2.0/api/python/index.html)
* [Spark R API (Roxygen2)](http://spark.apache.org/docs/2.2.0/api/R/index.html)
# 部署指南
\ No newline at end of file
# 集群模式概述
该文档给出了 Spark 如何在集群上运行、使之更容易来理解所涉及到的组件的简短概述。通过阅读 [应用提交指南](submitting-applications.html) 来学习关于在集群上启动应用。
# 组件
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 "Spark cluster components")
这里有几个关于这个架构需要注意的地方 :
1. 每个应用获取到它自己的 Executor 进程,它们会保持在整个应用的生命周期中并且在多个线程中运行 Task(任务)。这样做的优点是把应用互相隔离,在调度方面(每个 driver 调度它自己的 task)和 Executor 方面(来自不同应用的 task 运行在不同的 JVM 中)。然而,这也意味着若是不把数据写到外部的存储系统中的话,数据就不能够被不同的 Spark 应用(SparkContext 的实例)之间共享。
2. Spark 是不知道底层的 Cluster Manager 到底是什么类型的。只要它能够获得 Executor 进程,并且它们可以和彼此之间通信,那么即使是在一个也支持其它应用的 Cluster Manager(例如,Mesos / YARN)上来运行它也是相对简单的。
3. Driver 程序必须在自己的生命周期内(例如,请参阅 [在网络配置章节中的 spark.driver.port 章节](configuration.html#networking)。 监听和接受来自它的 Executor 的连接请求。同样的,driver 程序必须可以从 worker 节点上网络寻址(就是网络没问题)。
4. 因为 driver 调度了集群上的 task(任务),更好的方式应该是在相同的局域网中靠近 worker 的节点上运行。如果您不喜欢发送请求到远程的集群,倒不如打开一个 RPC 至 driver 并让它就近提交操作而不是从很远的 worker 节点上运行一个 driver。
# Cluster Manager 类型
系统目前支持三种 Cluster Manager:
* [Standalone](spark-standalone.html) – 包含在 Spark 中使得它更容易来安装集群的一个简单的 Cluster Manager。
* [Apache Mesos](running-on-mesos.html) – 一个通用的 Cluster Manager,它也可以运行 Hadoop MapReduce 和其它服务应用。
* [Hadoop YARN](running-on-yarn.html) –Hadoop 2 中的 resource manager(资源管理器)。
* [Kubernetes (experimental)](https://github.com/apache-spark-on-k8s/spark) – 除了上述之外,还有 Kubernetes 的实验支持。 Kubernetes 提供以容器为中心的基础设施的开源平台。 Kubernetes 的支持正在 apache-spark-on-k8s Github 组织中积极开发。有关文档,请参阅该项目的 README。
# 提交应用程序
使用 spark-submit 脚本可以提交应用至任何类型的集群。在 [application submission guide](submitting-applications.html) 介绍了如何做到这一点。
# 监控
每个 driver 都有一个 Web UI,通常在端口 4040 上,可以显示有关正在运行的 task,executor,和存储使用情况的信息。 只需在 Web 浏览器中的`http://<driver-node>:4040` 中访问此 UI。[监控指南](monitoring.html) 中还介绍了其他监控选项。
# Job 调度
Spark 即可以在应用间(Cluster Manager 级别),也可以在应用内(如果多个计算发生在相同的 SparkContext 上时)控制资源分配。 在 [任务调度概述](job-scheduling.html) 中更详细地描述了这一点。
# 术语
下表总结了您将看到的用于引用集群概念的术语:
| Term(术语) | Meaning(含义) |
| --- | --- |
| Application | 用户构建在 Spark 上的程序。由集群上的一个 driver 程序和多个 executor 组成。 |
| Application jar | 一个包含用户 Spark 应用的 Jar。有时候用户会想要去创建一个包含他们应用以及它的依赖的 “uber jar”。用户的 Jar 应该没有包括 Hadoop 或者 Spark 库,然而,它们将会在运行时被添加。 |
| Driver program | 该进程运行应用的 main() 方法并且创建了 SparkContext。 |
| Cluster manager | 一个外部的用于获取集群上资源的服务。(例如,Standlone Manager,Mesos,YARN) |
| Deploy mode | 根据 driver 程序运行的地方区别。在 “Cluster” 模式中,框架在群集内部启动 driver。在 “Client” 模式中,submitter(提交者)在 Custer 外部启动 driver。 |
| Worker node | 任何在集群中可以运行应用代码的节点。 |
| Executor | 一个为了在 worker 节点上的应用而启动的进程,它运行 task 并且将数据保持在内存中或者硬盘存储。每个应用有它自己的 Executor。 |
| Task | 一个将要被发送到 Executor 中的工作单元。 |
| Job | 一个由多个任务组成的并行计算,并且能从 Spark action 中获取响应(例如 `save`, `collect`); 您将在 driver 的日志中看到这个术语。 |
| Stage | 每个 Job 被拆分成更小的被称作 stage(阶段) 的 task(任务) 组,stage 彼此之间是相互依赖的(与 MapReduce 中的 map 和 reduce stage 相似)。您将在 driver 的日志中看到这个术语。 |
\ No newline at end of file
# Submitting Applications
在 script in Spark的 `bin` 目录中的`spark-submit` 脚本用与在集群上启动应用程序。它可以通过一个统一的接口使用所有 Spark 支持的 [cluster managers](cluster-overview.html#cluster-manager-types),所以您不需要专门的为每个[cluster managers](cluster-overview.html#cluster-manager-types)配置您的应用程序。
# 打包应用依赖
如果您的代码依赖了其它的项目,为了分发代码到 Spark 集群中您将需要将它们和您的应用程序一起打包。为此,创建一个包含您的代码以及依赖的 assembly jar(或者 “uber” jar)。无论是 [sbt](https://github.com/sbt/sbt-assembly) 还是 [Maven](http://maven.apache.org/plugins/maven-shade-plugin/) 都有 assembly 插件。在创建 assembly jar 时,列出 Spark 和 Hadoop的依赖为`provided`。它们不需要被打包,因为在运行时它们已经被 Cluster Manager 提供了。如果您有一个 assembled jar 您就可以调用 `bin/spark-submit` 脚本(如下所示)来传递您的 jar。
对于 Python 来说,您可以使用 `spark-submit``--py-files` 参数来添加 `.py`, `.zip``.egg` 文件以与您的应用程序一起分发。如果您依赖了多个 Python 文件我们推荐将它们打包成一个 `.zip` 或者 `.egg` 文件。
# 用 spark-submit 启动应用
如果用户的应用程序被打包好了,它可以使用 `bin/spark-submit` 脚本来启动。这个脚本负责设置 Spark 和它的依赖的 classpath,并且可以支持 Spark 所支持的不同的 Cluster Manager 以及 deploy mode(部署模式):
```
./bin/spark-submit \
--class <main-class> \
--master <master-url> \
--deploy-mode <deploy-mode> \
--conf <key>=<value> \
... # other options
<application-jar> \
[application-arguments]
```
一些常用的 options(选项)有 :
* `--class`: 您的应用程序的入口点(例如。 `org.apache.spark.examples.SparkPi`)
* `--master`: 集群的 [master URL](#master-urls) (例如 `spark://23.195.26.187:7077`)
* `--deploy-mode`: 是在 worker 节点(`cluster`) 上还是在本地作为一个外部的客户端(`client`) 部署您的 driver(默认: `client`) **†**
* `--conf`: 按照 key=value 格式任意的 Spark 配置属性。对于包含空格的 value(值)使用引号包 “key=value” 起来。
* `application-jar`: 包括您的应用以及所有依赖的一个打包的 Jar 的路径。该 URL 在您的集群上必须是全局可见的,例如,一个 `hdfs://` path 或者一个 `file://` 在所有节点是可见的。
* `application-arguments`: 传递到您的 main class 的 main 方法的参数,如果有的话。
**†** 常见的部署策略是从一台 gateway 机器物理位置与您 worker 在一起的机器(比如,在 standalone EC2 集群中的 Master 节点上)来提交您的应用。在这种设置中, `client` 模式是合适的。在 `client` 模式中,driver 直接运行在一个充当集群 client 的 `spark-submit` 进程内。应用程序的输入和输出直接连到控制台。因此,这个模式特别适合那些设计 REPL(例如,Spark shell)的应用程序。
另外,如果您从一台远离 worker 机器的机器(例如,本地的笔记本电脑上)提交应用程序,通常使用 `cluster` 模式来降低 driver 和 executor 之间的延迟。目前,Standalone 模式不支持 Cluster 模式的 Python 应用。
对于 Python 应用,在 `&lt;application-jar&gt;` 的位置简单的传递一个 `.py` 文件而不是一个 JAR,并且可以用 `--py-files` 添加 Python `.zip``.egg` 或者 `.py` 文件到 search path(搜索路径)。
这里有一些选项可用于特定的 [cluster manager](cluster-overview.html#cluster-manager-types) 中。例如, [Spark standalone cluster](spark-standalone.html)`cluster` 部署模式, 您也可以指定 `--supervise` 来确保 driver 在 non-zero exit code 失败时可以自动重启。为了列出所有 `spark-submit`, 可用的选项,用 `--help`. 来运行它。这里是一些常见选项的例子 :
```
# 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
```
# Master URLs
传递给 Spark 的 master URL 可以使用下列格式中的一种 :
| Master URL | Meaning |
| --- | --- |
| `local` | 使用一个线程本地运行 Spark(即,没有并行性)。 |
| `local[K]` | 使用 K 个 worker 线程本地运行 Spark(理想情况下,设置这个值的数量为您机器的 core 数量)。 |
| `local[K,F]` | 使用 K 个 worker 线程本地运行 Spark并允许最多失败 F次 (查阅 [spark.task.maxFailures](configuration.html#scheduling) 以获取对该变量的解释) |
| `local[*]` | 使用更多的 worker 线程作为逻辑的 core 在您的机器上来本地的运行 Spark。 |
| `local[*,F]` | 使用更多的 worker 线程作为逻辑的 core 在您的机器上来本地的运行 Spark并允许最多失败 F次。 |
| `spark://HOST:PORT` | 连接至给定的 [Spark standalone cluster](spark-standalone.html) master. master。该 port(端口)必须有一个作为您的 master 配置来使用,默认是 7077。 |
| `spark://HOST1:PORT1,HOST2:PORT2` | 连接至给定的 [Spark standalone cluster with standby masters with Zookeeper](spark-standalone.html#standby-masters-with-zookeeper). 该列表必须包含由zookeeper设置的高可用集群中的所有master主机。该 port(端口)必须有一个作为您的 master 配置来使用,默认是 7077。 |
| `mesos://HOST:PORT` | 连接至给定的 [Mesos](running-on-mesos.html) 集群. 该 port(端口)必须有一个作为您的配置来使用,默认是 5050。或者,对于使用了 ZooKeeper 的 Mesos cluster 来说,使用 `mesos://zk://...`. 。使用 `--deploy-mode cluster`, 来提交,该 HOST:PORT 应该被配置以连接到 [MesosClusterDispatcher](running-on-mesos.html#cluster-mode). |
| `yarn` | 连接至一个 [YARN](running-on-yarn.html) cluster in `client` or `cluster` mode 取决于 `--deploy-mode`. 的值在 client 或者 cluster 模式中。该 cluster 的位置将根据 `HADOOP_CONF_DIR` 或者 `YARN_CONF_DIR` 变量来找到。 |
# 从文件中加载配置
`spark-submit` 脚本可以从一个 properties 文件加载默认的 [Spark configuration values](configuration.html) 并且传递它们到您的应用中去。默认情况下,它将从 Spark 目录下的 `conf/spark-defaults.conf` 读取配置。更多详细信息,请看 [加载默认配置](configuration.html#loading-default-configurations).
加载默认的 Spark 配置,这种方式可以消除某些标记到 `spark-submit`. 的必要性。例如,如果 `spark.master` 属性被设置了,您可以在`spark-submit`中安全的省略 `--master` 配置 . 一般情况下,明确设置在 `SparkConf` 上的配置值的优先级最高,然后是传递给 `spark-submit`的值, 最后才是 default value(默认文件)中的值。
如果您不是很清楚其中的配置设置来自哪里,您可以通过使用 `--verbose` 选项来运行 `spark-submit` 打印出细粒度的调试信息。
# 高级的依赖管理
在使用 `spark-submit` 时,使用 `--jars` 选项包括的应用程序的 jar 和任何其它的 jar 都将被自动的传输到集群。在 `--jars` 后面提供的 URL 必须用逗号分隔。该列表会被包含到 driver 和 executor 的 classpath 中。 `--jars` 不支持目录的形式。
Spark 使用下面的 URL 格式以允许传播 jar 时使用不同的策略 :
* **file:** - 绝对路径和 `file:/` URI 通过 driver 的 HTTP file server 提供服务,并且每个 executor 会从 driver 的 HTTP server 拉取这些文件。
* **hdfs:**, **http:**, **https:**, **ftp:** - 如预期的一样拉取下载文件和 JAR
* **local:** - 一个用 local:/ 开头的 URL 预期作在每个 worker 节点上作为一个本地文件存在。这样意味着没有网络 IO 发生,并且非常适用于那些已经被推送到每个 worker 或通过 NFS,GlusterFS等共享的大型的 file/JAR。
N注意,那些 JAR 和文件被复制到 working directory(工作目录)用于在 executor 节点上的每个 SparkContext。这可以使用最多的空间显著量随着时间的推移,将需要清理。在 Spark On YARN 模式中,自动执行清理操作。在 Spark standalone 模式中,可以通过配置 `spark.worker.cleanup.appDataTtl` 属性来执行自动清理。
用户也可以通过使用 `--packages`来提供一个逗号分隔的 maven coordinates(maven 坐标)以包含任何其它的依赖。在使用这个命令时所有可传递的依赖将被处理。其它的 repository(或者在 SBT 中被解析的)可以使用 `--repositories`该标记添加到一个逗号分隔的样式中。 (注意,对于那些设置了密码保护的库,在一些情况下可以在库URL中提供验证信息,例如 `https://user:password@host/...`.以这种方式提供验证信息需要小心。) 这些命令可以与 `pyspark`, `spark-shell``spark-submit` 配置会使用以包含 Spark Packages(Spark 包)。 对于 Python 来说,也可以使用 `--py-files` 选项用于分发 `.egg`, `.zip``.py` libraries 到 executor 中。
# 更多信息
如果您已经部署了您的应用程序,[集群模式概述](cluster-overview.html) 描述了在分布式执行中涉及到的组件,以及如何去监控和调试应用程序。
\ No newline at end of file
# 部署模式
\ No newline at end of file
# Spark Standalone Mode
* [安装 Spark Standalone 集群](#安装-spark-standalone-集群)
* [手动启动一个集群](#手动启动一个集群)
* [集群启动脚本](#集群启动脚本)
* [提交应用程序到集群中](#提交应用程序到集群中)
* [启动 Spark 应用程序](#启动-spark-应用程序)
* [Resource Scheduling(资源调度)](#resource-scheduling资源调度)
* [监控和日志](#监控和日志)
* [与 Hadoop 集成](#与-hadoop-集成)
* [配置网络安全端口](#配置网络安全端口)
* [高可用性](#高可用性)
* [使用 ZooKeeper 备用 Masters](#使用-zookeeper-备用-masters)
* [用本地文件系统做单节点恢复](#用本地文件系统做单节点恢复)
Spark 除了运行在 Mesos 或者 YARN 上以外,Spark 还提供了一个简单的 standalone 部署模式。您可以手动启动 master 和 worker 来启动 standalone 集群,或者使用我们提供的 [launch scripts](#cluster-launch-scripts) 脚本。可以为了测试而在单个机器上运行这些进程。
# 安装 Spark Standalone 集群
安装 Spark Standalone 集群,您只需要将编译好的版本部署在集群中的每个节点上。您可以获取 Spark 的每个版本的预编译版本或者自己编译 [build it yourself](building-spark.html).
# 手动启动一个集群
您可以启动一个 standalone master server 通过执行下面的代码:
```
./sbin/start-master.sh
```
一旦启动,master 将会为自己打印出一个 `spark://HOST:PORT` URL,您可以使用它来连接 workers,或者像传递 “master” 参数一样传递到 `SparkContext` 。您在 master 的web UI 上也会找到这个 URL ,默认情况下是 [http://localhost:8080](http://localhost:8080)
类似地,您可以启动一个或多个 workers 并且通过下面的代码连接到 master :
```
./sbin/start-slave.sh <master-spark-URL>
```
在您启动一个 worker 之后,就可以通过 master 的 web UI ( 默认情况下是 [http://localhost:8080](http://localhost:8080))查看到了。您可以看到列出的新的 node (节点),以及其 CPU 的数量和数量(为操作系统留下了 1 GB 的空间)。
最后,下面的配置选项可以传递给 master 和 worker :
| Argument(参数) | Meaning(含义) |
| --- | --- |
| `-h HOST`, `--host HOST` | 监听的 Hostname |
| `-i HOST`, `--ip HOST` | 监听的 Hostname (已弃用, 请使用 -h or --host) |
| `-p PORT`, `--port PORT` | 监听的服务 Port (端口) (默认: master 是 7077 , worker 是随机的) |
| `--webui-port PORT` | web UI 的端口(默认: master 是 8080 , worker 是 8081) |
| `-c CORES`, `--cores CORES` | Spark 应用程序在机器上可以使用的全部的 CPU 核数(默认是全部可用的);这个选项仅在 worker 上可用 |
| `-m MEM`, `--memory MEM` | Spark 应用程序可以使用的内存数量,格式像 1000M 或者 2G(默认情况是您的机器内存数减去 1 GB);这个选项仅在 worker 上可用 |
| `-d DIR`, `--work-dir DIR` | 用于 scratch space (暂存空间)和作业输出日志的目录(默认是:SPARK_HOME/work);这个选项仅在 worker 上可用 |
| `--properties-file FILE` | 自定义的 Spark 配置文件加载目录(默认:conf/spark-defaults.conf) |
# 集群启动脚本
要使用启动脚本启动 Spark standalone 集群,你应该首先在 Spark 目录下创建一个叫做 conf/slaves 的文件,这个文件中必须包含所有你想要启动的 Spark workers 的机器的 hostname ,每个 hostname 占一行。 如果 conf/slaves 不存在,启动脚本默认启动单个机器(localhost),这对于测试是有效的。 注意, master 机器通过 ssh 访问所有的 worker 机器。默认情况下,ssh 是 parallel (并行)运行的并且需要配置无密码(使用一个私钥)的访问。 如果您没有设置无密码访问,您可以设置环境变量 SPARK_SSH_FOREGROUND 并且为每个 worker 提供一个密码。
一旦您创建了这个文件,您就可以启动或者停止您的集群使用下面的 shell 脚本,基于 Hadoop 的部署脚本,并在 `SPARK_HOME/sbin` 中可用:
* `sbin/start-master.sh` - 在执行的机器上启动一个 master 实例。
* `sbin/start-slaves.sh` - 在 `conf/slaves` 文件中指定的每个机器上启动一个 slave 实例。
* `sbin/start-slave.sh` - 在执行的机器上启动一个 slave 实例。
* `sbin/start-all.sh` - 启动一个 master 和上面说到的一定数量 slaves 。
* `sbin/stop-master.sh` - 停止通过 `sbin/start-master.sh` 脚本启动的 master。
* `sbin/stop-slaves.sh` - 停止在 `conf/slaves` 文件中指定的所有机器上的 slave 实例。
* `sbin/stop-all.sh` - 停止 master 和上边说到的 slaves 。
注意,这些脚本必须在您想要运行 Spark master 的机器上执行,而不是您本地的机器。
您可以通过在 `conf/spark-env.sh` 中设置环境变量来进一步配置集群。利用 `conf/spark-env.sh.template` 文件来创建这个文件,然后将它复制到所有的 worker 机器上使设置有效。下面的设置是可用的:
| Environment Variable (环境变量) | Meaning(含义) |
| --- | --- |
| `SPARK_MASTER_HOST` | 绑定 master 到一个指定的 hostname 或者 IP 地址,例如一个 public hostname 或者 IP 。 |
| `SPARK_MASTER_PORT` | 在不同的端口上启动 master (默认:7077) |
| `SPARK_MASTER_WEBUI_PORT` | master 的 web UI 的端口(默认:8080) |
| `SPARK_MASTER_OPTS` | 仅应用到 master 上的配置属性,格式是 "-Dx=y" (默认是:none)。查看下面的列表可能选项。 |
| `SPARK_LOCAL_DIRS` | Spark 中 "scratch" space(暂存空间)的目录,包括 map 的输出文件和存储在磁盘上的 RDDs 。这必须在您的系统中的一个快速的,本地的磁盘上。这也可以是逗号分隔的不同磁盘上的多个目录的列表。 |
| `SPARK_WORKER_CORES` | 机器上 Spark 应用程序可以使用的全部的 cores(核)的数量。(默认:全部的核可用) |
| `SPARK_WORKER_MEMORY` | 机器上 Spark 应用程序可以使用的全部的内存数量,例如 `1000m``2g`(默认:全部的内存减去 1 GB);注意每个应用程序的_individual(独立)_内存是使用 `spark.executor.memory` 属性进行配置的。 |
| `SPARK_WORKER_PORT` | 在一个指定的 port (端口)上启动 Spark worker (默认: random(随机)) |
| `SPARK_WORKER_WEBUI_PORT` | worker 的 web UI 的 Port (端口)(默认:8081) |
| `SPARK_WORKER_DIR` | 运行应用程序的目录,这个目录中包含日志和暂存空间(default: SPARK_HOME/work) |
| `SPARK_WORKER_OPTS` | 仅应用到 worker 的配置属性,格式是 "-Dx=y" (默认:none)。查看下面的列表的可能选项。 |
| `SPARK_DAEMON_MEMORY` | 分配给 Spark master 和 worker 守护进程的内存。(默认: 1g) |
| `SPARK_DAEMON_JAVA_OPTS` | Spark master 和 worker 守护进程的 JVM 选项,格式是 "-Dx=y" (默认:none) |
| `SPARK_PUBLIC_DNS` | Spark master 和 worker 的公开 DNS 名称。(默认:none) |
**注意:** 启动脚本现在还不支持 Windows 。要在 Windows 上运行一个 Spark 集群,需要手动启动 master 和 workers 。
SPARK_MASTER_OPTS 支持以下系统属性:
| Property Name(属性名称) | Default(默认) | Meaning(含义) |
| --- | --- | --- |
| `spark.deploy.retainedApplications` | 200 | 展示的已完成的应用程序的最大数量。旧的应用程序将会从 UI 中被删除以满足限制。
|
| `spark.deploy.retainedDrivers` | 200 | 展示已完成的 drivers 的最大数量。老的 driver 会从 UI 删除掉以满足限制。
|
| `spark.deploy.spreadOut` | true | 这个选项控制 standalone 集群 manager 是应该跨界店 spread (传播)应用程序还是应该努力将应用程序整合到尽可能少的节点上。在 HDFS 中, Spreading 是数据本地化的更好的选择,但是对于计算密集型的负载,整合会更有效率。
|
| `spark.deploy.defaultCores` | (infinite) | 如果没有设置 `spark.cores.max` ,在 Spark 的 standalone 模式下默认分配给应用程序的 cores (核)数。如果没有设置,应用程序将总是获得所有的可用核,除非设置了 `spark.cores.max` 。在共享集群中设置较低的核数,可用于防止用户 grabbing (抓取)整个集群。
|
| `spark.deploy.maxExecutorRetries` | 10 | 限制在 standalone 集群 manager 删除一个不正确地应用程序之前可能发生的 back-to-back 执行器失败的最大次数。如果一个应用程序有任何正在运行的执行器,则它永远不会被删除。如果一个应用程序经历过超过 `spark.deploy.maxExecutorRetries` 次的连续失败,没有执行器成功开始运行在这些失败之间,并且应用程序没有运行着的执行器,然后 standalone 集群 manager 将会移除这个应用程序并将它标记为失败。要禁用这个自动删除功能,设置`spark.deploy.maxExecutorRetries``-1`
|
| `spark.worker.timeout` | 60 | standalone 部署模式下 master 如果没有接收到心跳,认为一个 worker 丢失的间隔时间,秒数。 |
SPARK_WORKER_OPTS 支持以下的系统属性:
| Property Name | Default | Meaning |
| --- | --- | --- |
| `spark.worker.cleanup.enabled` | false | 激活周期性清空 worker / application 目录。注意,这只影响 standalone 模式,因为 YARN 工作方式不同。只有已停止的应用程序的目录会被清空。 |
| `spark.worker.cleanup.interval` | 1800 (30 minutes) | 在本地机器上,worker 控制清空老的应用程序的工作目录的时间间隔,以秒计数。 |
| `spark.worker.cleanup.appDataTtl` | 604800 (7 days, 7 * 24 * 3600) | 每个 worker 中应用程序工作目录的保留时间。这是一个 Live 时间,并且应该取决于您拥有的可用的磁盘空间量。应用程序的日志和 jars 都会被下载到应用程序的工作目录。随着时间的推移,这个工作目录会很快填满磁盘空间,特别是如果您经常运行作业。 |
| `spark.worker.ui.compressedLogFileLengthCacheSize` | 100 | 对于压缩日志文件,只能通过未压缩文件来计算未压缩文件。 Spark 缓存未压缩日志文件的未压缩文件大小。此属性控制缓存的大小。 |
# 提交应用程序到集群中
要在 Spark 集群中运行一个应用程序,只需要简单地将 master 的 `spark://IP:PORT` URL 传递到 [`SparkContext` constructor](programming-guide.html#initializing-spark)
要针对集群运行交互式 Spark shell ,运行下面的命令:
```
./bin/spark-shell --master spark://IP:PORT
```
您还可以传递一个选项 `--total-executor-cores &lt;numCores&gt;` 来控制 spark-shell 在集群上使用的 cores (核)数。
# 启动 Spark 应用程序
[`spark-submit` 脚本](submitting-applications.html) 提供了最简单的方法将一个编译好的 Spark 应用程序提交到集群中。对于 standalone 集群,Spark 目前支持两种部署模式。在 `client` 模式下,driver 在与 client 提交应用程序相同的进程中启动。在 `cluster` 模式下,driver 是集群中的某个 Worker 中的进程中启动,并且 client 进程将会在完成提交应用程序的任务之后退出,而不需要等待应用程序完成再退出。
如果您的应用程序是通过 Spark 提交来启动的,则应用程序的 jar 将自动启动分发给所有的 worker 节点。对于您的应用程序依赖的其他的 jar ,您应该通过 `--jars` 标志使用逗号作为分隔符(例如 `--jars jar1,jar2`)来指定它们。 要控制应用程序的配置或执行环境,请参阅 [Spark Configuration](configuration.html)
另外,standalone `cluster` 模式支持自动重新启动应用程序如果它是以非零的退出码退出的。要使用此功能,您可以在启动您的应用程序的时候将 `--supervise` 标志传入 `spark-submit` 。然后,如果您想杀死一个重复失败的应用程序,您可以使用如下方式:
```
./bin/spark-class org.apache.spark.deploy.Client kill <master url> <driver ID>
```
您可以查看 driver ID 通过 standalone Master web UI 在 `http://&lt;master url&gt;:8080`
# Resource Scheduling(资源调度)
standalone 集群模式当前只支持一个简单的跨应用程序的 FIFO 调度。 然而,为了允许多个并发的用户,您可以控制每个应用程序能用的最大资源数。 默认情况下,它将获取集群中的 _all_ cores (核),这只有在某一时刻只允许一个应用程序运行时才有意义。您可以通过 `spark.cores.max`[SparkConf](configuration.html#spark-properties) 中设置 cores (核)的数量。例如:
```
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=<value>"
```
这在用户没有配置最大独立核数的共享的集群中是有用的。
# 监控和日志
Spark 的 standalone 模式提供了一个基于 web 的用户接口来监控集群。master 和每个 worker 都有它自己的显示集群和作业信息的 web UI 。 默认情况下,您可以通过 master 的 8080 端口来访问 web UI 。这个端口可以通过配置文件修改或者通过命令行选项修改。
此外,对于每个作业的详细日志输出也会写入到每个 slave 节点的工作目录中。(默认是 `SPARK_HOME/work`)。你会看到每个作业的两个文件,分别是 `stdout``stderr` ,其中所有输出都写入其控制台。
# 与 Hadoop 集成
您可以运行 Spark 集成到您现有的 Hadoop 集群,只需在同一台机器上将其作为单独的服务启动。要从 Spark 访问 Hadoop 的数据,只需要使用 hdfs:// URL (通常为 `hdfs://&lt;namenode&gt;:9000/path`, 但是您可以在您的 Hadoop Namenode 的 web UI 中找到正确的 URL 。) 或者,您可以为 Spark 设置一个单独的集群,并且仍然可以通过网络访问 HDFS ;这将比磁盘本地访问速度慢,但是如果您仍然在同一个局域网中运行(例如,您将 Hadoop 上的每个机架放置几台 Spark 机器),可能不会引起关注。
# 配置网络安全端口
Spark 对网络的需求比较高,并且一些环境对于使用严格的防火墙设置有严格的要求,请查看 [security page](security.html#configuring-ports-for-network-security)
# 高可用性
默认情况下, standalone 调度集群对于 Worker 的失败(对于 Spark 本身可以通过将其移动到其他 worker 来说是失败的工作而言)是有弹性的。但是,调度程序使用 Master 进行调度决策,并且(默认情况下)汇创建一个单点故障:如果 Master 崩溃,新的应用程序将不会被创建。为了规避这一点,我们有两个高可用性方案,详细说明如下。
## 使用 ZooKeeper 备用 Masters
**概述**
使用 ZooKeeper 提供的 leader election (领导选举)和一些 state storage (状态存储),在连接到同一 ZooKeeper 实例的集群中启动多个 Masters 。一个节点将被选举为 “leader” 并且其他节点将会维持备用模式。如果当前的 leader 宕掉了,另一个 Master 将会被选举,恢复老的 Master 的状态,并且恢复调度。整个恢复过程(从第一个 leader 宕掉开始)应该会使用 1 到 2 分钟。注意此延迟仅仅影响调度 _new_ 应用程序 – 在 Master 故障切换期间已经运行的应用程序不受影响。
详细了解如何开始使用 ZooKeeper [这里](http://zookeeper.apache.org/doc/trunk/zookeeperStarted.html)
**配置**
为了启用这个恢复模式,您可以在 spark-env 中设置 SPARK_DAEMON_JAVA_OPTS 通过配置 `spark.deploy.recoveryMode` 和相关的 spark.deploy.zookeeper.* 配置。 有关这些配置的更多信息,请参阅 [配置文档](configuration.html#deploy)
可能的陷阱:如果您在您的集群中有多个 Masters 但是没有正确地配置 Masters 使用 ZooKeeper , Masters 将无法相互发现,并认为它们都是 leader 。这将不会形成一个健康的集群状态(因为所有的 Masters 将会独立调度)。
**细节**
在您设置了 ZooKeeper 集群之后,实现高可用性是很简单的。只需要在具有相同 ZooKeeper 配置(ZooKeeper URL 和 目录)的不同节点上启动多个 Master 进程。Masters 随时可以被添加和删除。
为了调度新的应用程序或者添加新的 Worker 到集群中,他们需要知道当前的 leader 的 IP 地址。这可以通过简单地传递一个您在一个单一的进程中传递的 Masters 的列表来完成。例如,您可以启动您的 SparkContext 指向 `spark://host1:port1,host2:port2` 。这将导致您的 SparkContext 尝试去注册两个 Masters – 如果 `host1` 宕掉,这个配置仍然是正确地,因为我们将会发现新的 leader `host2`
在 “registering with a Master (使用 Master 注册)” 与正常操作之间有一个重要的区别。当启动的时候,一个应用程序或者 Worker 需要使用当前的 lead Master 找到并且注册。一旦它成功注册,它就是 “in the system(在系统中)”了(即存储在了 ZooKeeper 中)。如果发生故障切换,新的 leader 将会联系所有值钱已经注册的应用程序和 Workers 来通知他们领导层的变化,所以他们甚至不知道新的 Master 在启动时的存在。
由于这个属性,新的 Masters 可以在任何时间创建,唯一需要担心的是,_new_ 应用程序和 Workers 可以找到它注册,以防其成为 leader 。一旦注册了之后,您将被照顾。
## 用本地文件系统做单节点恢复
**概述**
ZooKeeper 是生产级别的高可用性的最佳方法,但是如果您只是想要重新启动 Master 服务器,如果 Master 宕掉,FILESYSTEM 模式将会关注它。当应用程序和 Workers 注册了之后,它们具有写入提供的目录的足够的状态,以便在重新启动 Master 进程的时候可以恢复它们。
**配置**
为了启用此恢复模式,你可以使用以下配置在 spark-env 中设置 SPARK_DAEMON_JAVA_OPTS :
| System property(系统属性) | Meaning(含义) |
| --- | --- |
| `spark.deploy.recoveryMode` | 设置为 FILESYSTEM 以启用单节点恢复模式(默认:NONE) |
| `spark.deploy.recoveryDirectory` | Spark 将存储恢复状态的目录,可以从 Master 的角度访问。 |
**细节**
* 该解决方案可以与像 [monit](http://mmonit.com/monit/) 这样的过程 monitor/manager 一起使用,或者只是通过重新启动手动恢复。
* 尽管文件系统恢复似乎比完全没有任何恢复更好,但是对于某些特定的开发或者实验目的,此模式可能不太适合。特别是,通过 stop-master.sh 杀死 master 并不会清除其恢复状态,所以每当重新启动一个新的 Master 时,它将进入恢复模式。如果需要等待所有先前注册的 Worker/clients 超时,这可能会将启动时间增加 1 分钟。
* 虽然没有正式的支持,你也可以挂载 NFS 目录作为恢复目录。如果 original Master w安全地死亡,则您可以在不同的节点上启动 Master ,这将正确恢复所有以前注册的 Workers/applications (相当于 ZooKeeper 恢复)。然而,未来的应用程序必须能够找到新的 Master 才能注册。
\ No newline at end of file
此差异已折叠。
此差异已折叠。
# 其它
* [Amazon EC2](https://github.com/amplab/spark-ec2): 花费大约5分钟的时间让您在EC2上启动一个集群的脚本
* [Kubernetes (experimental)](https://github.com/apache-spark-on-k8s/spark): 在 Kubernetes 之上部署 Spark
\ No newline at end of file
# 更多
\ No newline at end of file
# 编程指南
\ No newline at end of file
此差异已折叠。
# Monitoring and Instrumentation
有几种方法来监视Spark应用程序:Web UI,metrics和外部工具。
# Web 界面
每个SparkContext都会启动一个Web UI,默认端口为4040,显示有关应用程序的有用信息。这包括:
* 调度器阶段和任务的列表
* RDD 大小和内存使用的概要信息
* 环境信息
* 正在运行的执行器的信息
您可以通过在Web浏览器中打开 `http://&lt;driver-node&gt;:4040` 来访问此界面。 如果多个SparkContexts在同一主机上运行,则它们将绑定到连续的端口从4040(4041,4042等)开始。
请注意,默认情况下此信息仅适用于运行中的应用程序。要在事后还能通过Web UI查看,请在应用程序启动之前,将`spark.eventLog.enabled`设置为true。 这配置Spark持久存储以记录Spark事件,再通过编码该信息在UI中进行显示。
## 事后查看
仍然可以通过Spark的历史服务器构建应用程序的UI, 只要应用程序的事件日志存在。 您可以通过执行以下命令启动历史服务器:
```
./sbin/start-history-server.sh
```
默认情况下,会在 `http://&lt;server-url&gt;:18080` 创建一个Web 界面 ,显示未完成、完成以及其他尝试的任务信息。
当使用file-system提供程序类(见下面 `spark.history.provider`)时,基本日志记录目录必须在`spark.history.fs.logDirectory`配置选项中提供,并且应包含每个代表应用程序的事件日志的子目录。
Spark任务本身必须配置启用记录事件,并将其记录到相同共享的可写目录下。 例如,如果服务器配置了日志目录`hdfs://namenode/shared/spark-logs`,那么客户端选项将是:
```
spark.eventLog.enabled true
spark.eventLog.dir hdfs://namenode/shared/spark-logs
```
history server 可以配置如下:
### 环境变量
| 环境变量 | 含义 |
| --- | --- |
| `SPARK_DAEMON_MEMORY` | history server 内存分配(默认值:1g) |
| `SPARK_DAEMON_JAVA_OPTS` | history server JVM选项(默认值:无) |
| `SPARK_PUBLIC_DNS` | history server 公共地址。如果没有设置,应用程序历史记录的链接可能会使用服务器的内部地址,导致链接断开(默认值:无)。 |
| `SPARK_HISTORY_OPTS` | `spark.history.*` history server 配置选项(默认值:无) |
### Spark配置选项
| 属性名称 | 默认 | 含义 |
| --- | --- | --- |
| spark.history.provider | `org.apache.spark.deploy.history.FsHistoryProvider` | 执行应用程序历史后端的类的名称。 目前只有一个实现,由Spark提供,它查找存储在文件系统中的应用程序日志。 |
| spark.history.fs.logDirectory | file:/tmp/spark-events | 为了文件系统的历史提供者,包含要加载的应用程序事件日志的目录URL。 这可以是local `file://` 路径, HDFS `hdfs://namenode/shared/spark-logs` 或者是 Hadoop API支持的替代文件系统。 |
| spark.history.fs.update.interval | 10s | 文件系统历史的提供者在日志目录中检查新的或更新的日志期间。 更短的时间间隔可以更快地检测新的应用程序,而不必更多服务器负载重新读取更新的应用程序。 一旦更新完成,完成和未完成的应用程序的列表将反映更改。 |
| spark.history.retainedApplications | 50 | 在缓存中保留UI数据的应用程序数量。 如果超出此上限,则最早的应用程序将从缓存中删除。 如果应用程序不在缓存中,如果从UI 界面访问它将不得不从磁盘加载。 |
| spark.history.ui.maxApplications | Int.MaxValue | 在历史记录摘要页面上显示的应用程序数量。 应用程序UI仍然可以通过直接访问其URL,即使它们不显示在历史记录摘要页面上。 |
| spark.history.ui.port | 18080 | history server 的Web界面绑定的端口。 |
| spark.history.kerberos.enabled | false | 表明 history server 是否应该使用kerberos进行登录。 如果 history server 正在访问安全的Hadoop集群上的HDFS文件,则需要这样做。 如果这是真的,它使用配置 `spark.history.kerberos.principal``spark.history.kerberos.keytab` |
| spark.history.kerberos.principal | (none) | history server 的Kerberos主要名称。 |
| spark.history.kerberos.keytab | (none) | history server 的kerberos keytab文件的位置。 |
| spark.history.ui.acls.enable | false | 指定是否应检查acls授权查看应用程序的用户。 如果启用,则进行访问控制检查,无论单个应用程序在运行时为 `spark.ui.acls.enable` 设置了什么。 应用程序所有者将始终有权查看自己的应用程序和通过 `spark.ui.view.acls` 指定的任何用户和通过`spark.ui.view.acls.groups`,当应用程序运行时也将有权查看该应用程序。 如果禁用,则不进行访问控制检查。 |
| spark.history.ui.admin.acls | empty | 通过逗号来分隔具有对history server中所有Spark应用程序的查看访问权限的用户/管理员列表。 默认情况下只允许在运行时查看应用程序的用户可以访问相关的应用程序历史记录,配置的用户/管理员也可以具有访问权限。 在列表中添加 "*" 表示任何用户都可以拥有管理员的权限。 |
| spark.history.ui.admin.acls.groups | empty | 通过逗号来分隔具有对history server中所有Spark应用程序的查看访问权限的组的列表。 默认情况下只允许在运行时查看应用程序的组可以访问相关的应用程序历史记录,配置的组也可以具有访问权限。 在列表中放置 "*" 表示任何组都可以拥有管理员权限。 |
| spark.history.fs.cleaner.enabled | false | 指定 History Server是否应该定期从存储中清除事件日志。 |
| spark.history.fs.cleaner.interval | 1d | 文件系统 job history清洁程序多久检查要删除的文件。 如果文件比 `spark.history.fs.cleaner.maxAge` 更旧,那么它们将被删除。 |
| spark.history.fs.cleaner.maxAge | 7d | 较早的Job history文件将在文件系统历史清除程序运行时被删除。 |
| spark.history.fs.numReplayThreads | 25% of available cores | history server 用于处理事件日志的线程数。 |
请注意UI中所有的任务,表格可以通过点击它们的标题来排序,便于识别慢速任务,数据偏移等。
注意
1. history server 显示完成的和未完成的Spark作业。 如果应用程序在失败后进行多次尝试,将显示失败的尝试,以及任何持续未完成的尝试或最终成功的尝试。
2. 未完成的程序只会间歇性地更新。 更新的时间间隔由更改文件的检查间隔 (`spark.history.fs.update.interval`) 定义。 在较大的集群上,更新间隔可能设置为较大的值。 查看正在运行的应用程序的方式实际上是查看自己的Web UI。
3. 没有注册完成就退出的应用程序将被列出为未完成的,即使它们不再运行。如果应用程序崩溃,可能会发生这种情况。
4. 一个用于表示完成Spark作业的一种方法是明确地停止Spark Context (`sc.stop()`),或者在Python中使用 `with SparkContext() as sc:` 构造处理Spark上下文设置并拆除。
## REST API
除了在UI中查看指标之外,还可以使用JSON。 这为开发人员提供了一种简单的方法来为Spark创建新的可视化和监控工具。 JSON可用于运行的应用程序和 history server。The endpoints are mounted at `/api/v1`。 例如,对于 history server,它们通常可以在 `http://&lt;server-url&gt;:18080/api/v1` 访问,对于正在运行的应用程序,在 `http://localhost:4040/api/v1`
在API中,一个应用程序被其应用程序ID `[app-id]`引用。 当运行在YARN上时,每个应用程序可能会有多次尝试,但是仅针对群集模式下的应用程序进行尝试,而不是客户端模式下的应用程序。 YARN群集模式中的应用程序可以通过它们的 `[attempt-id]`来识别。 在下面列出的API中,当以YARN集群模式运行时,`[app-id]`实际上是 `[base-app-id]/[attempt-id]`,其中 `[base-app-id]`YARN应用程序ID。
| Endpoint | 含义 |
| --- | --- |
| `/applications` | 所有应用程序的列表。
`?status=[completed&#124;running]` 列出所选状态下的应用程序。
`?minDate=[date]` 列出最早的开始日期/时间。
`?maxDate=[date]` 列出最新开始日期/时间。
`?minEndDate=[date]` 列出最早的结束日期/时间。
`?maxEndDate=[date]` 列出最新结束日期/时间。
`?limit=[limit]` 限制列出的应用程序数量。
示例:
`?minDate=2015-02-10`
`?minDate=2015-02-03T16:42:40.000GMT`
`?maxDate=2015-02-11T20:41:30.000GMT`
`?minEndDate=2015-02-12`
`?minEndDate=2015-02-12T09:15:10.000GMT`
`?maxEndDate=2015-02-14T16:30:45.000GMT`
`?limit=10` |
| `/applications/[app-id]/jobs` | 给定应用程序的所有job的列表。
`?status=[running&#124;succeeded&#124;failed&#124;unknown]` 列出在特定状态下的job。 |
| `/applications/[app-id]/jobs/[job-id]` | 给定job的详细信息。 |
| `/applications/[app-id]/stages` | 给定应用程序的所有阶段的列表。
`?status=[active&#124;complete&#124;pending&#124;failed]` 仅列出状态的阶段。 |
| `/applications/[app-id]/stages/[stage-id]` | 给定阶段的所有尝试的列表。 |
| `/applications/[app-id]/stages/[stage-id]/[stage-attempt-id]` | 给定阶段的尝试详细信息。 |
| `/applications/[app-id]/stages/[stage-id]/[stage-attempt-id]/taskSummary` | 给定阶段尝试中所有任务的汇总指标。
`?quantiles` 用给定的分位数总结指标。
Example: `?quantiles=0.01,0.5,0.99` |
| `/applications/[app-id]/stages/[stage-id]/[stage-attempt-id]/taskList` | 给定阶段尝试的所有task的列表。
`?offset=[offset]&length=[len]` 列出给定范围内的task。
`?sortBy=[runtime&#124;-runtime]` task排序.
Example: `?offset=10&length=50&sortBy=runtime` |
| `/applications/[app-id]/executors` | 给定应用程序的所有活动executor的列表。 |
| `/applications/[app-id]/allexecutors` | 给定应用程序的所有(活动和死亡)executor的列表。 |
| `/applications/[app-id]/storage/rdd` | 给定应用程序的存储RDD列表。 |
| `/applications/[app-id]/storage/rdd/[rdd-id]` | 给定RDD的存储状态的详细信息。 |
| `/applications/[base-app-id]/logs` | 将给定应用程序的所有尝试的事件日志下载为一个zip文件。 |
| `/applications/[base-app-id]/[attempt-id]/logs` | 将特定应用程序尝试的事件日志下载为一个zip文件。 |
| `/applications/[app-id]/streaming/statistics` | streaming context的统计信息 |
| `/applications/[app-id]/streaming/receivers` | 所有streaming receivers的列表。 |
| `/applications/[app-id]/streaming/receivers/[stream-id]` | 给定receiver的详细信息。 |
| `/applications/[app-id]/streaming/batches` | 所有被保留batch的列表。 |
| `/applications/[app-id]/streaming/batches/[batch-id]` | 给定batch的详细信息。 |
| `/applications/[app-id]/streaming/batches/[batch-id]/operations` | 给定batch的所有输出操作的列表。 |
| `/applications/[app-id]/streaming/batches/[batch-id]/operations/[outputOp-id]` | 给定操作和给定batch的详细信息。 |
| `/applications/[app-id]/environment` | 给定应用程序环境的详细信息。 |
可检索的 job 和 stage 的数量被standalone Spark UI 的相同保留机制所约束。 `"spark.ui.retainedJobs"` 定义触发job垃圾收集的阈值,以及 `spark.ui.retainedStages` 限定stage。 请注意,垃圾回收在play时进行:可以通过增加这些值并重新启动history server来检索更多条目。
### API 版本控制策略
这些 endpoint已被强力版本化,以便更容易开发应用程序。 特别是Spark保证:
* endpoint 永远不会从一个版本中删除
* 任何给定 endpoint都不会删除个别字段
* 可以添加新的 endpoint
* 可以将新字段添加到现有 endpoint
* 将来可能会在单独的 endpoint添加新版本的api(例如: `api/v2`)。 新版本 _不_ 需要向后兼容。
* Api版本可能会被删除,但只有在至少一个与新的api版本共存的次要版本之后才可以删除。
请注意,即使在检查正在运行的应用程序的UI时,仍然需要 `applications/[app-id]`部分,尽管只有一个应用程序可用。 例如:要查看正在运行的应用程序的作业列表,您可以访问 `http://localhost:4040/api/v1/applications/[app-id]/jobs`。 这是为了在两种模式下保持路径一致。
# Metrics
Spark具有基于[Dropwizard Metrics Library](http://metrics.dropwizard.io/)的可配置metrics系统。 这允许用户将Spark metrics报告给各种接收器,包括HTTP,JMX和CSV文件。 metrics系统是通过配置文件进行配置的,Spark配置文件是Spark预计出现在 `$SPARK_HOME/conf/metrics.properties`上。 可以通过`spark.metrics.conf` [配置属性](configuration.html#spark-properties)指定自定义文件位置。 默认情况下,用于 driver或 executor metrics标准的根命名空间是 `spark.app.id`的值。 然而,通常用户希望能够跟踪 driver和executors的应用程序的metrics,这与应用程序ID(即:`spark.app.id`)很难相关,因为每次调用应用程序都会发生变化。 对于这种用例,可以为使用 `spark.metrics.namespace`配置属性的metrics报告指定自定义命名空间。 例如,如果用户希望将度量命名空间设置为应用程序的名称,则可以将`spark.metrics.namespace`属性设置为像 `${spark.app.name}`这样的值。 然后,该值会被Spark适当扩展,并用作度量系统的根命名空间。 非 driver和 executor的metrics标准永远不会以 `spark.app.id`为前缀,`spark.metrics.namespace`属性也不会对这些metrics有任何这样的影响。
Spark的metrics被分解为与Spark组件相对应的不同_instances_。 在每个实例中,您可以配置一组报告汇总指标。 目前支持以下实例:
* `master`: Spark standalone的 master进程。
* `applications`: 主机内的一个组件,报告各种应用程序。
* `worker`: Spark standalone的 worker进程。
* `executor`: A Spark executor.
* `driver`: Spark driver进程(创建SparkContext的过程)。
* `shuffleService`: The Spark shuffle service.
每个实例可以报告为 0 或更多 _sinks_。 Sinks包含在 `org.apache.spark.metrics.sink`包中:
* `ConsoleSink`: 将metrics信息记录到控制台。
* `CSVSink`: 定期将metrics数据导出到CSV文件。
* `JmxSink`: 注册在JMX控制台中查看的metrics。
* `MetricsServlet`: 在现有的Spark UI中添加一个servlet,以将数据作为JSON数据提供。
* `GraphiteSink`: 将metrics发送到Graphite节点。
* `Slf4jSink`: 将metrics标准作为日志条目发送到slf4j。
Spark还支持由于许可限制而不包含在默认构建中的Ganglia接收器:
* `GangliaSink`: 向Ganglia节点或 multicast组发送metrics。
要安装 `GangliaSink` ,您需要执行Spark的自定义构建。 _**请注意,通过嵌入此库,您将包括 [LGPL](http://www.gnu.org/copyleft/lesser.html)-licensed Spark包中的代码**_。 对于sbt用户,在构建之前设置 `SPARK_GANGLIA_LGPL`环境变量。 对于Maven用户,启用 `-Pspark-ganglia-lgpl`配置文件。 除了修改集群的Spark构建用户,应用程序还需要链接到 `spark-ganglia-lgpl`工件。
metrics配置文件的语法在示例配置文件 `$SPARK_HOME/conf/metrics.properties.template`中定义。
# 高级工具
可以使用几种外部工具来帮助描述Spark job的性能:
* 集群范围的监控工具,例如 [Ganglia](http://ganglia.sourceforge.net/)可以提供对整体集群利用率和资源瓶颈的洞察。例如,Ganglia仪表板可以快速显示特定工作负载是否为磁盘绑定,网络绑定或CPU绑定。
* 操作系统分析工具,如 [dstat](http://dag.wieers.com/home-made/dstat/),[iostat](http://linux.die.net/man/1/iostat) 和 [iotop](http://linux.die.net/man/1/iotop) 可以在单个节点上提供细粒度的分析。
* JVM实用程序,如 `jstack` 提供堆栈跟踪,`jmap`用于创建堆转储,`jstat`用于报告时间序列统计数据和`jconsole`用于可视化地浏览各种JVM属性对于那些合适的JVM内部使用是有用的。
\ No newline at end of file
# Tuning Spark
* [数据序列化](#数据序列化)
* [内存调优](#内存调优)
* [内存管理概述](#内存管理概述)
* [确定内存消耗](#确定内存消耗)
* [调整数据结构](#调整数据结构)
* [序列化 RDD 存储](#序列化-rdd-存储)
* [垃圾收集调整](#垃圾收集调整)
* [其他注意事项](#其他注意事项)
* [并行度水平](#并行度水平)
* [减少任务的内存使用](#减少任务的内存使用)
* [广播大的变量](#广播大的变量)
* [数据本地化](#数据本地化)
* [概要](#概要)
由于大多数 Spark 计算的内存性质, Spark 程序可能由集群中的任何资源( CPU ,网络带宽或内存)导致瓶颈。 通常情况下,如果数据有合适的内存,瓶颈就是网络带宽,但有时您还需要进行一些调整,例如 [以序列化形式存储 RDD](programming-guide.html#rdd-persistence) 来减少内存的使用。 本指南将涵盖两个主要的主题:数据序列化,这对于良好的网络性能至关重要,并且还可以减少内存使用和内存优化。 我们选几个较小的主题进行展开。
# 数据序列化
序列化在任何分布式应用程序的性能中起着重要的作用。 很慢的将对象序列化或消费大量字节的格式将会大大减慢计算速度。 通常,这可能是您优化 Spark 应用程序的第一件事。 Spark 宗旨在于方便和性能之间取得一个平衡(允许您使用操作中的任何 Java 类型)。 它提供了两种序列化库:
* [Java serialization](http://docs.oracle.com/javase/6/docs/api/java/io/Serializable.html): 默认情况下,使用 Java `ObjectOutputStream` 框架的 Spark 序列化对象,并且可以与您创建的任何实现 [`java.io.Serializable`](http://docs.oracle.com/javase/6/docs/api/java/io/Serializable.html) 的类一起使用。 您还可以通过扩展 [`java.io.Externalizable`](http://docs.oracle.com/javase/6/docs/api/java/io/Externalizable.html) 来更紧密地控制序列化的性能。 Java 序列化是灵活的,但通常相当缓慢,并导致许多类的大型序列化格式。
* [Kryo serialization](https://github.com/EsotericSoftware/kryo): Spark 也可以使用 Kryo 库(版本2)来更快地对对象进行序列化。 Kryo 比 Java 序列化(通常高达10x)要快得多,而且更紧凑,但并不支持所有的 `Serializable` 类型,并且需要先_注册_您将在程序中使用的类以获得最佳性能。
您可以通过使用 [SparkConf](configuration.html#spark-properties) 初始化作业 并进行调用来切换到使用 Kryo `conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")`。此设置配置用于不仅在工作节点之间进行洗牌数据的串行器,而且还将 RDD 序列化到磁盘。 Kryo 不是默认的唯一原因是因为自定义注册要求,但我们建议您尝试在任何网络密集型应用程序。自从 Spark 2.0.0 以来,我们在使用简单类型,简单类型的数组或字符串类型对RDD进行混洗时,内部使用 Kryo serializer 。
Spark 自动包含 Kryo 序列化器,用于 [Twitter chill](https://github.com/twitter/chill) 中 AllScalaRegistrar 涵盖的许多常用的核心 Scala 类。
要使用 Kryo 注册自己的自定义类,请使用该 `registerKryoClasses` 方法。
```
val conf = new SparkConf().setMaster(...).setAppName(...)
conf.registerKryoClasses(Array(classOf[MyClass1], classOf[MyClass2]))
val sc = new SparkContext(conf)
```
所述 [Kryo 文档](https://github.com/EsotericSoftware/kryo) 描述了更先进的注册选项,如添加自定义序列的代码。
如果您的对象很大,您可能还需要增加 `spark.kryoserializer.buffer` [配置](configuration.html#compression-and-serialization)。该值需要足够大才能容纳您将序列化的最大对象。
最后,如果您没有注册自定义类, Kryo 仍然可以工作,但它必须存储每个对象的完整类名称,这是浪费的。
# 内存调优
有三个方面的考虑在调整内存使用:该_量_的存储你的对象所使用的(你可能希望你的整个数据集,以适应在内存中),则_成本_访问这些对象,并且开销_垃圾收集_(如果你有高成交物品条款)。
默认情况下, Java 对象可以快速访问,但可以轻松地消耗比其字段中的 “raw” 数据多2-5倍的空间。这是由于以下几个原因:
* 每个不同的 Java 对象都有一个 “object header” ,它大约是16个字节,包含一个指向它的类的指针。对于一个数据很少的对象(比如说一个`Int`字段),这可以比数据大。
* Java `String` 在原始字符串数据上具有大约40字节的开销(因为它们存储在 `Char` 数组中并保留额外的数据,例如长度),并且由于 UTF-16 的内部使用而将每个字符存储为_两个_字节 `String` 编码。因此,一个10个字符的字符串可以容易地消耗60个字节。
* 公共收集类,例如 `HashMap``LinkedList` ,使用链接的数据结构,其中每个条目(例如: `Map.Entry` )存在”包装器”对象。该对象不仅具有 header ,还包括指针(通常为8个字节)到列表中的下一个对象。
* 原始类型的集合通常将它们存储为”盒装”对象,例如: `java.lang.Integer`
本节将从 Spark 的内存管理概述开始,然后讨论用户可以采取的具体策略,以便在他/她的应用程序中更有效地使用内存。具体来说,我们将描述如何确定对象的内存使用情况,以及如何改进数据结构,或通过以串行格式存储数据。然后我们将介绍调整 Spark 的缓存大小和 Java 垃圾回收器。
## 内存管理概述
Spark 中的内存使用大部分属于两类:执行和存储。执行存储器是指用于以混洗,连接,排序和聚合计算的存储器,而存储内存是指用于在集群中缓存和传播内部数据的内存。在 Spark 中,执行和存储共享一个统一的区域(M)。当没有使用执行存储器时,存储器可以获取所有可用的存储器,反之亦然。如果需要,执行可以驱逐存储,但只有在总存储内存使用量低于某个阈值(R)之前。换句话说, `R` 描述 `M` 缓存块永远不会被驱逐的区域。由于实施的复杂性,存储不得驱逐执行。
该设计确保了几个理想的性能。首先,不使用缓存的应用程序可以将整个空间用于执行,从而避免不必要的磁盘泄漏。第二,使用缓存的应用程序可以保留最小的存储空间(R),其中数据块不受驱逐。最后,这种方法为各种工作负载提供了合理的开箱即用性能,而不需要用户内部如何分配内存的专业知识。
虽然有两种相关配置,但典型用户不需要调整它们,因为默认值适用于大多数工作负载:
* `spark.memory.fraction` 表示大小 `M`(JVM堆空间 - 300MB)(默认为0.6)的一小部分。剩余的空间(40%)保留用于用户数据结构,Spark中的内部元数据,并且在稀疏和异常大的记录的情况下保护OOM错误。
* `spark.memory.storageFraction` 表示大小 `R``M` (默认为0.5)的一小部分。 `R``M` 缓存块中的缓存被执行驱逐的存储空间。
`spark.memory.fraction` 应该设置值,以便在 JVM 的旧版或”终身”版本中舒适地适应这一堆堆空间。有关详细信息,请参阅下面高级 GC 调优的讨论。
## 确定内存消耗
大小数据集所需的内存消耗量的最佳方式是创建 RDD ,将其放入缓存中,并查看 Web UI 中的“存储”页面。该页面将告诉您 RDD 占用多少内存。
为了估计特定对象的内存消耗,使用 `SizeEstimator``estimate` 方法这是用于与不同的数据布局试验修剪内存使用情况,以及确定的空间的广播变量将占据每个执行器堆的量是有用的。
## 调整数据结构
减少内存消耗的第一种方法是避免添加开销的 Java 功能,例如基于指针的数据结构和包装对象。有几种方法可以做到这一点:
1. 将数据结构设计为偏好对象数组和原始类型,而不是标准的 Java 或 Scala 集合类(例如: `HashMap` )。该 [fastutil](http://fastutil.di.unimi.it) 库提供方便的集合类基本类型是与 Java 标准库兼容。
2. 尽可能避免使用很多小对象和指针的嵌套结构。
3. 考虑使用数字 ID 或枚举对象而不是键的字符串。
4. 如果您的 RAM 小于32 GB,请设置 JVM 标志 `-XX:+UseCompressedOops` ,使指针为4个字节而不是8个字节。您可以添加这些选项 [`spark-env.sh`](configuration.html#environment-variables)
## 序列化 RDD 存储
当您的对象仍然太大而无法有效存储,尽管这种调整,减少内存使用的一个更简单的方法是以序列化形式存储它们,使用 [RDD 持久性 API](programming-guide.html#rdd-persistence) 中的序列化 StorageLevel ,例如: `MEMORY_ONLY_SER` 。 Spark 将会将每个 RDD 分区存储为一个大字节数组。以序列化形式存储数据的唯一缺点是访问时间较短,因为必须对每个对象进行反序列化。如果您想以序列化形式缓存数据,我们强烈建议[使用 Kryo](#data-serialization) ,因为它导致比 Java 序列化更小的尺寸(而且肯定比原 Java 对象)更小。
## 垃圾收集调整
当您的程序存储的 RDD 有很大的”流失”时, JVM 垃圾收集可能是一个问题。(程序中通常没有问题,只读一次 RDD ,然后在其上运行许多操作)。 当 Java 需要驱逐旧对象为新的对象腾出空间时,需要跟踪所有 Java 对象并找到未使用的。要记住的要点是,垃圾收集的成本与 Java 对象的数量成正比,因此使用较少对象的数据结构(例如: `Ints` 数组,而不是 `LinkedList` )大大降低了此成本。 一个更好的方法是如上所述以序列化形式持久化对象:现在每个 RDD 分区只有一个对象(一个字节数组)。 在尝试其他技术之前,如果 GC 是一个问题,首先要使用[序列化缓存](#serialized-rdd-storage)
由于任务的工作记忆(运行任务所需的空间)和缓存在节点上的 RDD 之间的干扰, GC 也可能是一个问题。我们将讨论如何控制分配给RDD缓存的空间来减轻这一点。
**测量 GC 的影响**
GC 调整的第一步是收集关于垃圾收集发生频率和GC花费的时间的统计信息。这可以通过添加 `-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps` 到 Java 选项来完成。(有关将 Java 选项传递给 Spark 作业的信息,请参阅[配置指南](configuration.html#Dynamically-Loading-Spark-Properties))下次运行 Spark 作业时,每当发生垃圾回收时,都会看到在工作日志中打印的消息。请注意,这些日志将在您的群集的工作节点上( `stdout` 在其工作目录中的文件中),而不是您的驱动程序。
**高级 GC 优化**
为了进一步调整垃圾收集,我们首先需要了解一些关于 JVM 内存管理的基本信息:
* Java堆空间分为两个区域 Young 和 Old 。 Young 一代的目的是持有短命的物体,而 Old 一代的目标是使用寿命更长的物体。
* Young 一代进一步分为三个区域[ Eden , Survivor1 , Survivor2 ]。
* 垃圾收集过程的简化说明:当 Eden 已满时, Eden 上运行了一个小型 GC ,并将 Eden 和 Survivor1 中存在的对象复制到 Survivor2 。幸存者地区被交换。如果一个对象足够老,或者 Survivor2 已满,则会移动到 Old 。最后,当 Old 接近满时,一个完整的 GC 被调用。
Spark 中 GC 调优的目的是确保只有长寿命的 RDD 存储在 Old 版本中,并且 Young 版本的大小足够存储短命期的对象。这将有助于避免使用完整的 GC 来收集任务执行期间创建的临时对象。可能有用的一些步骤是:
* 通过收集 GC 统计信息来检查垃圾收集是否太多。如果在任务完成之前多次调用完整的 GC ,这意味着没有足够的可用于执行任务的内存。
* 如果太小的集合太多,而不是很多主要的 GC ,为 Eden 分配更多的内存将会有所帮助。您可以将 Eden 的大小设置为对每个任务需要多少内存的估计。如果确定 Eden 的大小 `E` ,那么您可以使用该选项设置年轻一代的大小 `-Xmn=4/3*E` 。(按比例增加4/3是考虑幸存者地区使用的空间。)
* 在打印的 GC 统计信息中,如果 OldGen 接近于满,则通过降低减少用于缓存的内存量 `spark.memory.fraction` ; 缓存较少的对象比减慢任务执行更好。或者,考虑减少年轻一代的大小。这意味着 `-Xmn` 如果您将其设置为如上所述降低。如果没有,请尝试更改 JVM `NewRatio` 参数的值。许多 JVM 默认为2,这意味着 Old 版本占据堆栈的2/3。它应该足够大,使得该分数超过 `spark.memory.fraction`
* 尝试使用 G1GC 垃圾回收器 `-XX:+UseG1GC`。在垃圾收集是瓶颈的一些情况下,它可以提高性能. 请注意,对于大型 excutor 的堆大小,通过设置 -XX:G1HeapRegionSize 参数来增加 [G1 区域的大小](https://blogs.oracle.com/g1gc/entry/g1_gc_tuning_a_case) 是非常重要的
* 例如,如果您的任务是从 HDFS 读取数据,则可以使用从 HDFS 读取的数据块的大小来估计任务使用的内存量。请注意,解压缩块的大小通常是块大小的2或3倍。所以如果我们希望有3或4个任务的工作空间,而 HDFS 块的大小是128MB,我们可以估计 Eden 的大小`4*3*128MB`
* 监控垃圾收集的频率和时间如何随着新设置的变化而变化。
我们的经验表明, GC 调整的效果取决于您的应用程序和可用的内存量。有[更多的优化选项](http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html) 在线描述,但在较高的水平,管理完整的 GC 如何经常发生可以减少开销帮助。
可以通过`spark.executor.extraJavaOptions`在作业的配置中设置来指定执行器的 GC 调整标志。
# 其他注意事项
## 并行度水平
集群不会被充分利用,除非您将每个操作的并行级别设置得足够高。自动星火设置的 “地图” 任务的数量根据其大小对每个文件运行(尽管你可以通过可选的参数来控制它 `SparkContext.textFile` ,等等),以及用于分布式”减少”操作,如: `groupByKey``reduceByKey` ,它采用了最大父 RDD 的分区数。您可以将并行级别作为第二个参数传递(请参阅 [`spark.PairRDDFunctions`](api/scala/index.html#org.apache.spark.rdd.PairRDDFunctions) 文档),或者将 config 属性设置 `spark.default.parallelism` 为更改默认值。一般来说,我们建议您的群集中每个 CPU 内核有2-3个任务。
## 减少任务的内存使用
有时,您将得到一个 OutOfMemoryError ,因为您的 RDD 不适合内存,而是因为您的其中一个任务的工作集(如其中一个 reduce 任务`groupByKey`)太大。 Spark 的 shuffle 操作(`sortByKey``groupByKey``reduceByKey``join`,等)建立每个任务中的哈希表来进行分组,而这往往是很大的。这里最简单的解决方案是_增加并行级别_,以便每个任务的输入集都更小。 Spark 可以有效地支持短达200 ms 的任务,因为它可以将多个任务中的一个执行者JVM重用,并且任务启动成本低,因此您可以将并行级别安全地提高到集群中的核心数量。
## 广播大的变量
使用 可用的[广播功能](programming-guide.html#broadcast-variables) `SparkContext` 可以大大减少每个序列化任务的大小,以及在群集上启动作业的成本。如果您的任务使用其中的驱动程序中的任何大对象(例如:静态查找表),请考虑将其变为广播变量。 Spark 打印主机上每个任务的序列化大小,因此您可以查看该任务以决定您的任务是否过大; 一般任务大于20 KB大概值得优化。
## 数据本地化
数据本地化可能会对 Spark job 的性能产生重大影响。如果数据和在其上操作的代码在一起,则计算往往是快速的。但如果代码和数据分开,则必须移动到另一个。通常,代码大小远小于数据,因此将数据代码从一个地方寄送到另一个地方比一大块数据更快。 Spark 围绕数据局部性的一般原则构建其调度。
数据本地化是指数据和代码处理有多近。根据数据的当前位置有几个地方级别。从最近到最远的顺序:
* `PROCESS_LOCAL` 数据与运行代码在同一个 JVM 中。这是可能的最好的地方
* `NODE_LOCAL` 数据在同一个节点上。示例可能在同一节点上的 HDFS 或同一节点上的另一个执行程序中。这比 `PROCESS_LOCAL` 因为数据必须在进程之间移动慢一些
* `NO_PREF` 数据从任何地方同样快速访问,并且没有本地偏好
* `RACK_LOCAL` 数据位于同一机架上的服务器上。数据位于同一机架上的不同服务器上,因此需要通过网络发送,通常通过单个交换机发送
* `ANY` 数据在网络上的其他地方,而不在同一个机架中
Spark 喜欢将所有 task 安排在最佳的本地级别,但这并不总是可能的。在任何空闲 executor 中没有未处理数据的情况下, Spark 将切换到较低的本地级别。有两个选项: a )等待一个繁忙的 CPU 释放在相同服务器上的数据上启动任务,或者 b )立即在更远的地方启动一个新的任务,需要在那里移动数据。
Spark 通常做的是等待一个繁忙的 CPU 释放的希望。一旦超时,它将开始将数据从远处移动到可用的 CPU 。每个级别之间的回退等待超时可以在一个参数中单独配置或全部配置; 有关详细信息,请参阅[配置页面](configuration.html#scheduling) `spark.locality` 上的 参数。如果您的 task 很长,并且本地化差,您应该增加这些设置,但默认值通常会很好。
# 概要
这是一个简短的指南,指出调整 Spark 应用程序时应该了解的主要问题 - 最重要的是数据序列化和内存调整。对于大多数程序,以序列化形式切换到 Kryo 序列化和持久化数据将会解决大多数常见的性能问题。随时在 [Spark 邮件列表](https://spark.apache.org/community.html) 中询问有关其他调优最佳做法的信息。
\ No newline at end of file
# 作业调度
* [概述](#概述)
* [跨应用调度](#跨应用调度)
* [动态资源分配](#动态资源分配)
* [配置和部署](#配置和部署)
* [资源分配策略](#资源分配策略)
* [请求策略](#请求策略)
* [移除策略](#移除策略)
* [优雅的关闭Executor(执行器)](#优雅的关闭executor执行器)
* [应用内调度](#应用内调度)
* [公平调度资源池](#公平调度资源池)
* [资源池默认行为](#资源池默认行为)
* [配置资源池属性](#配置资源池属性)
# 概述
Spark 有好几计算资源调度的方式. 首先,回忆一下 [集群模式概述](cluster-overview.html), 每个Spark 应用(包含一个SparkContext实例)中运行了一些其独占的执行器(executor)进程. 集群管理器提供了Spark 应用之间的资源调度[scheduling across applications](#scheduling-across-applications). 其次, 在各个Spark应用内部,各个线程可能并发地通过action算子提交多个Spark作业(job).如果你的应用服务于网络请求,那这种情况是很常见的. 在Spark应用内部(对应同一个SparkContext)各个作业之间,Spark默认FIFO调度,同时也可以支持公平调度 [fair scheduler](#scheduling-within-an-application).
# 跨应用调度
如果在集群上运行,每个Spark应用都会SparkContext获得一批独占的执行器JVM,来运行其任务并存储数据. 如果有多个用户共享集群,那么会有很多资源分配相关的选项,如何设计还取觉于具体的集群管理器.
对Spark所支持的各个集群管理器而言,最简单的的资源分配,就是静态划分.这种方式就意味着,每个Spark应用都是设定一个最大可用资源总量,并且该应用在整个生命周期内都会占住这个资源.这种方式在 Spark’s独立部署 [standalone](spark-standalone.html)[YARN](running-on-yarn.html)调度,以及Mesos粗粒度模式下都可用.[coarse-grained Mesos mode](running-on-mesos.html#mesos-run-modes) . Resource allocation can be configured as follows, based on the cluster type:
* **Standalone mode:** 默认情况下,Spark应用在独立部署的集群中都会以FIFO(first-in-first-out)模式顺序提交运行,并且每个spark应用都会占用集群中所有可用节点.不过你可以通过设置spark.cores.max或者spark.deploy.defaultCores来限制单个应用所占用的节点个数.最后,除了可以控制对CPU的使用数量之外,还可以通过spark.executor.memory来控制各个应用的内存占用量.
* **Mesos:** 在Mesos中要使用静态划分的话,需要将spark.mesos.coarse设为true,同样,你也需要配置spark.cores.max来控制各个应用的CPU总数,以及spark.executor.memory来控制各个应用的内存占用.
* **YARN:** 在YARN中需要使用 –num-executors 选项来控制Spark应用在集群中分配的执行器的个数.对于单个执行器(executor)所占用的资源,可以使用 –executor-memory和–executor-cores来控制. Mesos上还有一种动态共享CPU的方式。在这种模式下,每个Spark应用的内存占用仍然是固定且独占的(仍由spark.exexcutor.memory决定),但是如果该Spark应用没有在某个机器上执行任务的话,那么其它应用可以占用该机器上的CPU。这种模式对集群中有大量不是很活跃应用的场景非常有效,例如:集群中有很多不同用户的Spark shell session.但这种模式不适用于低延时的场景,因为当Spark应用需要使用CPU的时候,可能需要等待一段时间才能取得对CPU的使用权。要使用这种模式,只需要在mesos://URL上设置spark.mesos.coarse属性为false即可。
值得注意的是,目前还没有任何一种资源分配模式支持跨Spark应用的内存共享。如果你想通过这种方式共享数据,我们建议你可以单独使用一个服务(例如:alluxio),这样就能实现多应用访问同一个RDD的数据。
## 动态资源分配
Spark 提供了一种基于负载来动态调节Spark应用资源占用的机制。这意味着,你的应用会在资源空闲的时间将其释放给集群,需要时再重新申请。这一特性在多个应用Spark集群资源的情况下特别有用.
这个特性默认是禁止的,但是在所有的粗粒度集群管理器上都是可用的,如:i.e. 独立部署模式[standalone mode](spark-standalone.html), [YARN mode](running-on-yarn.html), and 粗粒度模式[Mesos coarse-grained mode](running-on-mesos.html#mesos-run-modes).
### 配置和部署
要使用这一特性有两个前提条件。首先,你的应用必须设置spark.dynamicAllocation.enabled为true。其次,你必须在每个节点上启动external shuffle service,并将spark.shuffle.service.enabled设为true。external shuffle service 的目的是在移除executor的时候,能够保留executor输出的shuffle文件(本文后续有更新的描述 [below](job-scheduling.html#graceful-decommission-of-executors)). 启用external shuffle service 的方式在各个集群管理器上各不相同:
在Spark独立部署的集群中,你只需要在worker启动前设置spark.shuffle.service.enabled为true即可。
在Mesos粗粒度模式下,你需要在各个节点上运行$SPARK_HOME/sbin/start-mesos-shuffle-service.sh 并设置 spark.shuffle.service.enabled为true即可. 例如, 你可以在Marathon来启用这一功能。
在YARN模式下,需要按以下步骤在各个NodeManager上启动: [here](running-on-yarn.html#configuring-the-external-shuffle-service).
所有其它的配置都是可选的,在spark.dynamicAllocation._和spark.shuffle.service._这两个命明空间下有更加详细的介绍 [configurations page](configuration.html#dynamic-allocation).
### 资源分配策略
总体上来说,Spark应该在执行器空闲时将其关闭,而在后续要用时再申请。因为没有一个固定的方法,可以预测一个执行器在后续是否马上会被分配去执行任务,或者一个新分配的执行器实际上是空闲的,所以我们需要一个试探性的方法,来决定是否申请或是移除一个执行器。
#### 请求策略
一个启用了动态分配的Spark应用会有等待任务需要调度的时候,申请额外的执行器。在这种情况下,必定意味着已有的执行器已经不足以同时执行所有未完成的任务。
Spark会分轮次来申请执行器。实际的资源申请,会在任务挂起spark.dynamicAllocation.schedulerBacklogTimeout秒后首次触发,其后如果等待队列中仍有挂起的任务,则每过spark.dynamicAllocation.sustainedSchedulerBacklogTimeout秒后触发一次资源申请。另外,每一轮申请的执行器个数以指数形式增长。例如:一个Spark应用可能在首轮申请1个执行器,后续的轮次申请个数可能是2个、4个、8个….。
采用指数级增长策略的原因有两个:第一,对于任何一个Spark应用如果只需要多申请少数几个执行器的话,那么必须非常谨慎的启动资源申请,这和TCP慢启动有些类似;第二,如果一旦Spark应用确实需要申请多个执行器的话,那么可以确保其所需的计算资源及时增长。
#### 移除策略
移除执行器的策略就简单得多了。Spark应用会在某个执行器空闲超过 spark.dynamicAllocation.executorIdleTimeout秒后将其删除,在大多数情况下,执行器的移除条件和申请条件都是互斥的,也就是说,执行器在有等待执行任务挂起时,不应该空闲。
### 优雅的关闭Executor(执行器)
非动态分配模式下,执行器可能的退出原因有执行失败或是相关Spark应用已经退出。不管是哪种原因,执行器的所有状态都已经不再需要,可以丢弃掉。但是在动态分配的情况下,执行器有可能在Spark应用运行期间被移除。这时候,如果Spark应用尝试去访问该执行器存储的状态,就必须重算这一部分数据。因此,Spark需要一种机制,能够优雅的关闭执行器,同时还保留其状态数据。
这种需求对于混洗操作尤其重要。混洗过程中,Spark 执行器首先将 map 输出写到本地磁盘,同时执行器本身又是一个文件服务器,这样其他执行器就能够通过该执行器获得对应的 map 结果数据。一旦有某些任务执行时间过长,动态分配有可能在混洗结束前移除任务异常的执行器,而这些被移除的执行器对应的数据将会被重新计算,但这些重算其实是不必要的。
要解决这一问题,就需要用到 external shuffle service ,该服务在 Spark 1.2 引入。该服务在每个节点上都会启动一个不依赖于任何 Spark 应用或执行器的独立进程。一旦该服务启用,Spark 执行器不再从各个执行器上获取 shuffle 文件,转而从这个 service 获取。这意味着,任何执行器输出的混洗状态数据都可能存留时间比对应的执行器进程还长。
除了混洗文件之外,执行器也会在磁盘或者内存中缓存数。一旦执行器被移除,其缓存数据将无法访问。这个问题目前还没有解决。或许在未来的版本中,可能会采用外部混洗服务类似的方法,将缓存数据保存在堆外存储中以解决这一问题。
# 应用内调度
在指定的 Spark 应用内部(对应同一 SparkContext 实例),多个线程可能并发地提交 Spark 作业(job)。在本节中,作业(job)是指,由 Spark action 算子(如 : collect)触发的一系列计算任务的集合。Spark 调度器是完全线程安全的,并且能够支持 Spark 应用同时处理多个请求(比如 : 来自不同用户的查询)。
默认,Spark 应用内部使用 FIFO 调度策略。每个作业被划分为多个阶段(stage)(例如 : map 阶段和 reduce 阶段),第一个作业在其启动后会优先获取所有的可用资源,然后是第二个作业再申请,再第三个……。如果前面的作业没有把集群资源占满,则后续的作业可以立即启动运行,否则,后提交的作业会有明显的延迟等待。
不过从 Spark 0.8 开始,Spark 也能支持各个作业间的公平(Fair)调度。公平调度时,Spark 以轮询的方式给每个作业分配资源,因此所有的作业获得的资源大体上是平均分配。这意味着,即使有大作业在运行,小的作业再提交也能立即获得计算资源而不是等待前面的作业结束,大大减少了延迟时间。这种模式特别适合于多用户配置。 要启用公平调度器,只需设置一下 SparkContext 中 spark.scheduler.mode 属性为 FAIR 即可 :
```
val conf = new SparkConf().setMaster(...).setAppName(...)
conf.set("spark.scheduler.mode", "FAIR")
val sc = new SparkContext(conf)
```
## 公平调度资源池
公平调度器还可以支持将作业分组放入资源池(pool),然后给每个资源池配置不同的选项(如 : 权重)。这样你就可以给一些比较重要的作业创建一个“高优先级”资源池,或者你也可以把每个用户的作业分到一组,这样一来就是各个用户平均分享集群资源,而不是各个作业平分集群资源。Spark 公平调度的实现方式基本都是模仿 [Hadoop Fair Scheduler](http://hadoop.apache.org/docs/current/hadoop-yarn/hadoop-yarn-site/FairScheduler.html). 来实现的。
默认情况下,新提交的作业都会进入到默认资源池中,不过作业对应于哪个资源池,可以在提交作业的线程中用 SparkContext.setLocalProperty 设定 spark.scheduler.pool 属性。示例代码如下 :
```
// Assuming sc is your SparkContext variable
sc.setLocalProperty("spark.scheduler.pool", "pool1")
```
一旦设好了局部属性,所有该线程所提交的作业(即 : 在该线程中调用action算子,如 : RDD.save/count/collect 等)都会使用这个资源池。这个设置是以线程为单位保存的,你很容易实现用同一线程来提交同一用户的所有作业到同一个资源池中。同样,如果需要清除资源池设置,只需在对应线程中调用如下代码 :
```
sc.setLocalProperty("spark.scheduler.pool", null)
```
## 资源池默认行为
默认地,各个资源池之间平分整个集群的资源(包括 default 资源池),但在资源池内部,默认情况下,作业是 FIFO 顺序执行的。举例来说,如果你为每个用户创建了一个资源池,那么久意味着各个用户之间共享整个集群的资源,但每个用户自己提交的作业是按顺序执行的,而不会出现后提交的作业抢占前面作业的资源。
## 配置资源池属性
资源池的属性需要通过配置文件来指定。每个资源池都支持以下3个属性 :
* `schedulingMode`: 可以是 FIFO 或 FAIR,控制资源池内部的作业是如何调度的。
* `weight`: 控制资源池相对其他资源池,可以分配到资源的比例。默认所有资源池的 weight 都是 1。如果你将某个资源池的 weight 设为 2,那么该资源池中的资源将是其他池子的2倍。如果将 weight 设得很高,如 1000,可以实现资源池之间的调度优先级 – 也就是说,weight=1000 的资源池总能立即启动其对应的作业。
* `minShare`: 除了整体 weight 之外,每个资源池还能指定一个最小资源分配值(CPU 个数),管理员可能会需要这个设置。公平调度器总是会尝试优先满足所有活跃(active)资源池的最小资源分配值,然后再根据各个池子的 weight 来分配剩下的资源。因此,minShare 属性能够确保每个资源池都能至少获得一定量的集群资源。minShare 的默认值是 0。
资源池属性是一个 XML 文件,可以基于 conf/fairscheduler.xml.template 修改,然后在 [SparkConf](configuration.html#spark-properties). 的 spark.scheduler.allocation.file 属性指定文件路径:
```
conf.set("spark.scheduler.allocation.file", "/path/to/file")
```
资源池 XML 配置文件格式如下,其中每个池子对应一个 &lt;pool&gt;元素,每个资源池可以有其独立的配置 :&lt;/pool&gt;
```
<?xml version="1.0"?>
<allocations>
<pool name="production">
<schedulingMode>FAIR</schedulingMode>
<weight>1</weight>
<minShare>2</minShare>
</pool>
<pool name="test">
<schedulingMode>FIFO</schedulingMode>
<weight>2</weight>
<minShare>3</minShare>
</pool>
</allocations>
```
完整的例子可以参考 conf/fairscheduler.xml.template。注意,没有在配置文件中配置的资源池都会使用默认配置(schedulingMode : FIFO,weight : 1,minShare : 0)。
\ No newline at end of file
# Spark 安全
Spark 当前支持使用 shared secret(共享密钥)来 authentication(认证)。可以通过配置 `spark.authenticate` 参数来开启认证。这个参数用来控制 Spark 的通讯协议是否使用共享密钥来执行认证。这个认证是一个基本的握手,用来保证两侧具有相同的共享密钥然后允许通讯。如果共享密钥无法识别,他们将不能通讯。创建共享密钥的方法如下:
* 对于 Spark on [YARN](running-on-yarn.html) 的部署方式,配置 `spark.authenticate``true`,会自动生成和分发共享密钥。每个 application 会使用一个单独的共享密钥.
* 对于 Spark 的其他部署方式, 需要在每一个 nodes 配置 `spark.authenticate.secret` 参数. 这个密码将会被所有的 Master/Workers 和 aplication 使用.
## Web UI
Spark UI 可以通过 `spark.ui.filters` 设置使用 [javax servlet filters](http://docs.oracle.com/javaee/6/api/javax/servlet/Filter.html) 和采用通过 [SSL settings](security.html#ssl-configuration) 启用 [https/SSL](http://en.wikipedia.org/wiki/HTTPS) 来进行安全保护。
### 认证
当 UI 中有一些不允许其他用户看到的数据时,用户可能想对 UI 进行安全防护。用户指定的 javax servlet filter 可以对用户进行身份认证,用户一旦登入,Spark 可以比较与这个用户相对应的视图 ACLs 来确认是否授权用户访问 UI。配置项 `spark.acls.enable`,`spark.ui.view.acls``spark.ui.view.acls.groups` 控制 ACLs 的行为。注意,启动 application 的用户具有使用 UI 视图的访问权限。在 YARN 上,Spark UI 使用标准的 YARN web application 代理机制可以通过任何已安装的 Hadoop filters 进行认证。
Spark 也支持修改 ACLs 来控制谁具有修改一个正在运行的 Spark application 的权限。这些权限包括 kill 这个 application 或者一个 task。以上功能通过配置 `spark.acls.enable``spark.modify.acls``spark.modify.acls.groups` 来控制。注意如果你已经认证登入 UI,为了使用 UI 上的 kill 按钮,必须先添加这个用户到 modify acls 和 view acls。在 YARN 上,modify acls 通过 YARN 接口传入并控制谁具有 modify 权限。Spark 允许在 acls 中指定多个对所有的 application 都具有 view 和 modify 权限的管理员,通过选项 `spark.admin.acls``spark.admin.acls.groups` 来控制。这样做对于一个有帮助用户调试 applications 的管理员或者支持人员的共享集群,非常有帮助。
## 事件日志
如果你的 applications 使用事件日志,事件日志的的位置必须手动创建同时具有适当的访问权限(`spark.eventLog.dir`)。如果想对这些日志文件做安全保护,目录的权限应该设置为 `drwxrwxrwxt`。目录的属主应该是启动 history server 的高级用户,同时组权限应该仅限于这个高级用户组。这将允许所有的用户向目录中写入文件,同时防止删除不是属于自己的文件(权限字符t为防删位)。事件日志将会被 Spark 创建,只有特定的用户才就有读写权限。
## 加密
Spark 支持 HTTP SSL 协议。SASL 加密用于块传输服务和 RPC 端。也可以加密 Shuffle 文件。
### SSL 配置
SSL 配置是分级组织的。用户可以对所有的通讯协议配置默认的 SSL 设置,除非被特定协议的设置覆盖掉。这样用户可以很容易的为所有的协议提供通用的设置,无需禁用每个单独配置的能力。通用的 SSL 设置在 Spark 配置文件的 `spark.ssl` 命名空间中。下表描述了用于覆盖特定组件默认配置的命名空间:
| Config Namespace(配置空间) | Component(组件) |
| --- | --- |
| `spark.ssl.fs` | 文件下载客户端 (用于从启用了 HTTPS 的服务器中下载 jars 和 files). |
| `spark.ssl.ui` | Spark application Web UI |
| `spark.ssl.standalone` | Standalone Master / Worker Web UI |
| `spark.ssl.historyServer` | History Server Web UI |
所有的SSL选项可以在 [配置页面](configuration.html) 里查询到。SSL 必须在所有的节点进行配置,对每个使用特定协议通讯的组件生效。
### YARN mode
key-store 可以在客户端侧准备好,然后作为 application 的一部分通过 executor 进行分发和使用。因为用户能够通过使用 `spark.yarn.dist.files` 或者 `spark.yarn.dis.archives` 配置选项,在 YARN上 启动 application 之前部署文件。加密和传输这些文件的责任在 YARN 一侧,与 Spark 无关。
为了一个长期运行的应用比如 Spark Streaming 应用能够写 HDFS,需要通过分别设置 `--principal``--keytab` 参数传递 principal 和 keytab 给 `spark-submit`。传入的 keytab 会通过 Hadoop Distributed Cache 拷贝到运行 Application 的 Master(这是安全的 - 如果 YARN 使用 SSL 配置同时启用了 HDFS 加密)。Kerberos 会使用这个 principal 和 keytab 周期的更新登陆信息,同时 HDFS 需要的授权 tokens 会周期生成,因此应用可以持续的写入 HDFS。
### Standalone mode
用户需要为 master 和 slaves 提供 key-stores 和相关配置选项。必须通过附加恰当的 Java 系统属性到 `SPARK_MASTER_OPTS``SPARK_WORKER_OPTS` 环境变量中,或者只在 `SPARK_DAEMON_JAVA_OPTS` 中。在这种模式下,用户可以允许 executors 使用从派生它的 worker 继承来的 SSL 设置。可以通过设置 `spark.ssl.useNodeLocalConf``true` 来完成。如果设置这个参数,用户在客户端侧提供的设置不会被 executors 使用。
### 准备 key-stores
可以使用 `keytool` 程序生成 key-stores。这个工具的使用说明在 [这里](https://docs.oracle.com/javase/7/docs/technotes/tools/solaris/keytool.html)。为 standalone 部署方式配置 key-stores 和 trust-store 最基本的步骤如下:
* 为每个 node 生成 keys pair
* 在每个 node 上导出 key pair 的 public key(公钥)到一个文件中
* 导入以上生成的所有的公钥到一个单独的 trust-store
* 在所有的节点上分发 trust-store
### 配置 SASL 加密
当认证(`sprk.authenticate`)开启的时候,块传输支持 SASL 加密。通过在 application 配置中设置 `spark.authenticate.enableSaslEncryption``true` 来开启 SASL 加密。
当使用外部 shuffle 服务,需要在 shuffle 服务配置中通过设置 `spark.network.sasl.serverAlwaysEncrypt``true` 来禁用未加密的连接。如果这个选项开启,未设置使用 SASL 加密的 application 在链接到 shuffer 服务的时候会失败。
## 针对网络安全配置端口
Spark 严重依赖 network,同时一些环境对使用防火墙有严格的要求。下面使一些 Spark 网络通讯使用的主要的端口和配置方式.
### Standalone mode only
| From | To | Default Port(默认端口) | Purpose(目的) | Configuration Setting(配置设置) | Notes(注意) |
| --- | --- | --- | --- | --- | --- |
| Browser | Standalone Master | 8080 | Web UI | `spark.master.ui.port /
SPARK_MASTER_WEBUI_PORT` | Jetty-based. Standalone mode only. |
| Browser | Standalone Worker | 8081 | Web UI | `spark.worker.ui.port /
SPARK_WORKER_WEBUI_PORT` | Jetty-based. Standalone mode only. |
| Driver /
Standalone Worker | Standalone Master | 7077 | Submit job to cluster /
Join cluster | `SPARK_MASTER_PORT` | Set to "0" to choose a port randomly. Standalone mode only. |
| Standalone Master | Standalone Worker | (random) | Schedule executors | `SPARK_WORKER_PORT` | Set to "0" to choose a port randomly. Standalone mode only. |
### All cluster managers
| From | To | Default Port(默认端口) | Purpose(目的) | Configuration Setting(配置设置) | Notes(注意) |
| --- | --- | --- | --- | --- | --- |
| Browser | Application | 4040 | Web UI | `spark.ui.port` | Jetty-based |
| Browser | History Server | 18080 | Web UI | `spark.history.ui.port` | Jetty-based |
| Executor /
Standalone Master | Driver | (random) | Connect to application /
Notify executor state changes | `spark.driver.port` | Set to "0" to choose a port randomly. |
| Executor / Driver | Executor / Driver | (random) | Block Manager port | `spark.blockManager.port` | Raw socket via ServerSocketChannel |
更多关于安全配置参数方面的细节请参考 [配置页面](configuration.html)。安全方面的实施细节参考 [`org.apache.spark.SecurityManager`](https://github.com/apache/spark/tree/master/core/src/main/scala/org/apache/spark/SecurityManager.scala).
\ No newline at end of file
# 硬件配置
Spark 开发者都会遇到一个常见问题,那就是如何为 Spark 配置硬件。然而正确的硬件配置取决于使用的场景,我们提出以下建议。
# 存储系统
因为大多数 Spark 作业都很可能必须从外部存储系统(例如 Hadoop 文件系统或者 HBase)读取输入的数据,所以部署 Spark 时**尽可能靠近这些系统**是很重要的。我们建议如下 :
* 如果可以,在 HDFS 相同的节点上运行 Spark 。最简单的方法是在相同节点上设置 Spark [独立集群模式](spark-standalone.html),并且配置 Spark 和 Hadoop 的内存和 CPU 的使用以避免干扰(Hadoop 的相关选项为 : 设置每个任务内存大小的选项 `mapred.child.java.opts` 以及设置任务数量的选项 `mapred.tasktracker.map.tasks.maximum``mapred.tasktracker.reduce.tasks.maximum`)。当然您也可以在常用的集群管理器(比如 [Mesos](running-on-mesos.html) 或者 [YARN](running-on-yarn.html))上运行 Hadoop 和 Spark。
* 如果不可以在相同的节点上运行,建议在与 HDFS 相同的局域网中的不同节点上运行 Spark 。
* 对于低延迟数据存储(如HBase),在这些存储系统不同的节点上运行计算作业来可能更有利于避免干扰。
# 本地磁盘
虽然 Spark 可以在内存中执行大量计算,但是他仍然使用本地磁盘来存储不适合内存存储的数据以及各个阶段的中间结果。我们建议每个节点配置 **4-8** 个磁盘,并且不使用 RAID 配置(只作为单独挂载点)。在 Linux 中,使用 [noatime选项](http://www.centos.org/docs/5/html/Global_File_System/s2-manage-mountnoatime.html) 挂载磁盘以减少不必要的写入。在 Spark 中,[配置](configuration.html) `spark.local.dir` 变量为逗号分隔的本地磁盘列表。如果您正在运行 HDFS,可以使用与 HDFS 相同的磁盘。
# 内存
一般来说,Spark 可以在每台机器 **8GB 到数百 GB** 内存的任何地方正常运行。在所有情况下,我们建议只为 Spark 分配最多75% 的内存;其余部分供操作系统和缓存区高速缓存存储器使用。
您需要多少内存取决于您的应用程序。如果您需要确定的应用程序中某个特定数据集占用内存的大小,您可以把这个数据集加载到一个 Spark RDD 中,然后在 Spark 监控 UI 页面(`http://&lt;driver-node&gt;:4040`)中的 Storage 选项卡下查看它在内存中的大小。需要注意的是,存储级别和序列化格式对内存使用量有很大的影响 - 如何减少内存使用量的建议,请参阅[调优指南](tuning.html)
最后,需要注意的是 Java 虚拟机在超过 200GB 的 RAM 时表现得并不好。如果您购置的机器有比这更多的 RAM ,您可以在每个节点上运行多个 Worker 的 JVM 实例。在 Spark 的 [standalone mode](spark-standalone.html) 下,您可以通过 `conf/spark-env.sh` 中的 `SPARK_WORKER_INSTANCES``SPARK_WORKER_CORES` 两个参数来分别设置每个节点的 Worker 数量和每个 Worker 使用的 Core 数量。
# 网络
根据我们的经验,当数据在内存中时,很多 Spark 应用程序跟网络有密切的关系。使用 **10 千兆位**以太网或者更快的网络是让这些应用程序变快的最佳方式。这对于 “distributed reduce” 类的应用程序来说尤其如此,例如 group-by 、reduce-by 和 SQL join。任何程序都可以在应用程序监控 UI 页面 (`http://&lt;driver-node&gt;:4040`) 中查看 Spark 通过网络传输的数据量。
# CPU Cores
因为 Spark 实行线程之间的最小共享,所以 Spark 可以很好地在每台机器上扩展数十个 CPU Core。您应该为每台机器至少配置 **8-16 个 Core**。根据您工作负载的 CPU 成本,您可能还需要更多:当数据都在内存中时,大多数应用程序就只跟 CPU 或者网络有关了。
\ No newline at end of file
# Accessing OpenStack Swift from Spark
Spark’s support for Hadoop InputFormat allows it to process data in OpenStack Swift using the same URI formats as in Hadoop. You can specify a path in Swift as input through a URI of the form `swift://container.PROVIDER/path`. You will also need to set your Swift security credentials, through `core-site.xml` or via `SparkContext.hadoopConfiguration`. Current Swift driver requires Swift to use Keystone authentication method.
# Configuring Swift for Better Data Locality
Although not mandatory, it is recommended to configure the proxy server of Swift with `list_endpoints` to have better data locality. More information is [available here](https://github.com/openstack/swift/blob/master/swift/common/middleware/list_endpoints.py).
# Dependencies
The Spark application should include `hadoop-openstack` dependency. For example, for Maven support, add the following to the `pom.xml` file:
```
<dependencyManagement>
...
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-openstack</artifactId>
<version>2.3.0</version>
</dependency>
...
</dependencyManagement>
```
# Configuration Parameters
Create `core-site.xml` and place it inside Spark’s `conf` directory. There are two main categories of parameters that should to be configured: declaration of the Swift driver and the parameters that are required by Keystone.
Configuration of Hadoop to use Swift File system achieved via
| Property Name | Value |
| --- | --- |
| fs.swift.impl | org.apache.hadoop.fs.swift.snative.SwiftNativeFileSystem |
Additional parameters required by Keystone (v2.0) and should be provided to the Swift driver. Those parameters will be used to perform authentication in Keystone to access Swift. The following table contains a list of Keystone mandatory parameters. `PROVIDER` can be any name.
| Property Name | Meaning | Required |
| --- | --- | --- |
| `fs.swift.service.PROVIDER.auth.url` | Keystone Authentication URL | Mandatory |
| `fs.swift.service.PROVIDER.auth.endpoint.prefix` | Keystone endpoints prefix | Optional |
| `fs.swift.service.PROVIDER.tenant` | Tenant | Mandatory |
| `fs.swift.service.PROVIDER.username` | Username | Mandatory |
| `fs.swift.service.PROVIDER.password` | Password | Mandatory |
| `fs.swift.service.PROVIDER.http.port` | HTTP port | Mandatory |
| `fs.swift.service.PROVIDER.region` | Keystone region | Mandatory |
| `fs.swift.service.PROVIDER.public` | Indicates if all URLs are public | Mandatory |
For example, assume `PROVIDER=SparkTest` and Keystone contains user `tester` with password `testing` defined for tenant `test`. Then `core-site.xml` should include:
```
<configuration>
<property>
<name>fs.swift.impl</name>
<value>org.apache.hadoop.fs.swift.snative.SwiftNativeFileSystem</value>
</property>
<property>
<name>fs.swift.service.SparkTest.auth.url</name>
<value>http://127.0.0.1:5000/v2.0/tokens</value>
</property>
<property>
<name>fs.swift.service.SparkTest.auth.endpoint.prefix</name>
<value>endpoints</value>
</property>
<name>fs.swift.service.SparkTest.http.port</name>
<value>8080</value>
</property>
<property>
<name>fs.swift.service.SparkTest.region</name>
<value>RegionOne</value>
</property>
<property>
<name>fs.swift.service.SparkTest.public</name>
<value>true</value>
</property>
<property>
<name>fs.swift.service.SparkTest.tenant</name>
<value>test</value>
</property>
<property>
<name>fs.swift.service.SparkTest.username</name>
<value>tester</value>
</property>
<property>
<name>fs.swift.service.SparkTest.password</name>
<value>testing</value>
</property>
</configuration>
```
Notice that `fs.swift.service.PROVIDER.tenant`, `fs.swift.service.PROVIDER.username`, `fs.swift.service.PROVIDER.password` contains sensitive information and keeping them in `core-site.xml` is not always a good approach. We suggest to keep those parameters in `core-site.xml` for testing purposes when running Spark via `spark-shell`. For job submissions they should be provided via `sparkContext.hadoopConfiguration`.
\ No newline at end of file
# 构建 Spark
* [构建 Apache Spark](#构建-apache-spark)
* [Apache Maven](#apache-maven)
* [设置 Maven 的内存使用](#设置-maven-的内存使用)
* [build/mvn](#buildmvn)
* [构建一个可运行的 Distribution 版本](#构建一个可运行的-distribution-版本)
* [指定 Hadoop 版本并启用 YARN](#指定-hadoop-版本并启用-yarn)
* [使用 Hive 和 JDBC 支持构建](#使用-hive-和-jdbc-支持构建)
* [打包没有 Hadoop 依赖关系的 YARN](#打包没有-hadoop-依赖关系的-yarn)
* [使用 Mesos 构建](#使用-mesos-构建)
* [使用 Scala 2.10 构建](#使用-scala-210-构建)
* [单独构建子模块](#单独构建子模块)
* [Continuous Compilation(连续编译)](#continuous-compilation连续编译)
* [使用 SBT 构建](#使用-sbt-构建)
* [加速编译](#加速编译)
* [加密文件系统](#加密文件系统)
* [IntelliJ IDEA 或 Eclipse](#intellij-idea-或-eclipse)
* [运行测试](#运行测试)
* [使用 SBT 测试](#使用-sbt-测试)
* [运行独立测试](#运行独立测试)
* [PySpark pip 可安装](#pyspark-pip-可安装)
* [使用 Maven 进行 PySpark 测试](#使用-maven-进行-pyspark-测试)
* [运行 R 测试](#运行-r-测试)
* [运行基于 Docker 的集成测试套装](#运行基于-docker-的集成测试套装)
# 构建 Apache Spark
## Apache Maven
基于 Maven 的构建是 Apache Spark 的参考构建。构建 Spark 需要 Maven 3.3.9 或者更高版本和 Java 8+ 。请注意,Spark 2.2.0 对于 Java 7 的支持已经删除了。
### 设置 Maven 的内存使用
您需要通过设置 `MAVEN_OPTS` 将 Maven 配置为比通常使用更多的内存:
```
export MAVEN_OPTS="-Xmx2g -XX:ReservedCodeCacheSize=512m"
```
(`ReservedCodeCacheSize` 设置是可选的,但是建议使用。) 如果您不讲这些参数加入到 `MAVEN_OPTS` 中,则可能会看到以下错误和警告:
```
[INFO] Compiling 203 Scala sources and 9 Java sources to /Users/me/Development/spark/core/target/scala-2.11/classes...
[ERROR] Java heap space -> [Help 1]
```
您可以通过如前所述设置 `MAVEN_OPTS` 变量来解决这些问题。
**注意:**
* 如果使用 `build/mvn` 但是没有设置 `MAVEN_OPTS` ,那么脚本会自动地将以上选项添加到 `MAVEN_OPTS` 环境变量。
* 即使不适用 `build/mvn` ,Spark 构建的 `test` 阶段也会自动将这些选项加入到 `MAVEN_OPTS` 中。
### build/mvn
Spark 现在与一个独立的 Maven 安装包封装到了一起,以便从位于 `build/` 目录下的源代码构建和部署 Spark 。该脚本将自动下载并设置所有必要的构建需求 ([Maven](https://maven.apache.org/)[Scala](http://www.scala-lang.org/)[Zinc](https://github.com/typesafehub/zinc)) 到本身的 `build/` 目录下。其尊重任何已经存在的 `mvn` 二进制文件,但是将会 pull down 其自己的 Scala 和 Zinc 的副本,不管是否满足适当的版本需求。`build/mvn` 的执行作为传递到 `mvn` 的调用,允许从以前的构建方法轻松转换。例如,可以像下边这样构建 Spark 的版本:
```
./build/mvn -DskipTests clean package
```
其他的构建例子可以在下边找到。
## 构建一个可运行的 Distribution 版本
想要创建一个像 [Spark 下载](http://spark.apache.org/downloads.html) 页面中的 Spark distribution 版本,并且使其能够运行,请使用项目 root 目录下的 `./dev/make-distribution.sh` 。它可以使用 Maven 的配置文件等等进行配置,如直接使用 Maven 构建。例如:
```
./dev/make-distribution.sh --name custom-spark --pip --r --tgz -Psparkr -Phadoop-2.7 -Phive -Phive-thriftserver -Pmesos -Pyarn
```
这将构建 Spark distribution 以及 Python pip 和 R 包。有关使用情况的更多信息,请运行 `./dev/make-distribution.sh --help`
## 指定 Hadoop 版本并启用 YARN
您可以通过 `hadoop.version` 属性指定要编译的 Hadoop 的确切版本。如果未指定, Spark 将默认构建为 Hadoop 2.6.X 。
您可以启用 `yarn` 配置文件,如果与 `hadoop.version` 不同的话,可以选择设置 `yarn.version` 属性。
示例:
```
# Apache Hadoop 2.6.X
./build/mvn -Pyarn -DskipTests clean package
# Apache Hadoop 2.7.X and later
./build/mvn -Pyarn -Phadoop-2.7 -Dhadoop.version=2.7.3 -DskipTests clean package
```
## 使用 Hive 和 JDBC 支持构建
要启用 Spark SQL 及其 JDBC server 和 CLI 的 Hive 集成,将 `-Phive``Phive-thriftserver` 配置文件添加到现有的构建选项中。 默认情况下, Spark 将使用 Hive 1.2.1 绑定构建。
```
# With Hive 1.2.1 support
./build/mvn -Pyarn -Phive -Phive-thriftserver -DskipTests clean package
```
## 打包没有 Hadoop 依赖关系的 YARN
默认情况下,由 `mvn package` 生成的 assembly directory (组件目录)将包含所有的Spark 依赖,包括 Hadoop 及其一些生态系统项目。 在 YARN 部署中,导致这些的多个版本显示在执行器 classpaths 上: Spark 组件的打包的版本和每个节点上的版本,包含在 `yarn.application.classpath` 中。 `hadoop-provided` 配置文件构建了不包括 Hadoop 生态系统项目的组件,就像 ZooKeeper 和 Hadoop 本身。
## 使用 Mesos 构建
```
./build/mvn -Pmesos -DskipTests clean package
```
## 使用 Scala 2.10 构建
要使用 Scala 2.10 编译的 Spark 软件包,请使用 `-Dscala-2.10` 属性:
```
./dev/change-scala-version.sh 2.10
./build/mvn -Pyarn -Dscala-2.10 -DskipTests clean package
```
请注意,Scala 2.10 的支持已经不再适用于 Spark 2.1.0 ,并且可能在 Spark 2.2.0 中被删除。
## 单独构建子模块
可以使用 `mvn -pl` 选项来构建 Spark 的子模块。
例如,您可以使用下面打代码来构建 Spark Streaming 模块:
```
./build/mvn -pl :spark-streaming_2.11 clean install
```
其中 `spark-streaming_2.11` 是在 `streaming/pom.xml` 文件中定义的 `artifactId`
## Continuous Compilation(连续编译)
我们使用支持增量和连续编译的 scala-maven-plugin 插件。例如:
```
./build/mvn scala:cc
```
这里应该运行连续编译(即等待更改)。然而这并没有得到广泛的测试。有几个需要注意的事情:
* 它只扫描路径 `src/main``src/test` (查看 [docs](http://scala-tools.org/mvnsites/maven-scala-plugin/usage_cc.html)),所以其只对含有该结构的某些子模块起作用。
* 您通常需要在工程的根目录运行 `mvn install` 在编译某些特定子模块时。这是因为依赖于其他子模块的子模块需要通过 `spark-parent` 模块实现。
因此,运行 `core` 子模块的连续编译总流程会像下边这样:
```
$ ./build/mvn install
$ cd core
$ ../build/mvn scala:cc
```
## 使用 SBT 构建
Maven 是推荐用于打包 Spark 的官方构建工具,是 _build of reference_ 。但是 SBT 支持日常开发,因为它可以提供更快的迭代编译。更多高级的开发者可能希望使用 SBT 。SBT 构建是从 Maven POM 文件导出的,因此也是相同的 Maven 配置文件和变量可以设置来控制 SBT 构建。 例如:
```
./build/sbt package
```
为了避免在每次需要重新编译时启动 sbt 的开销,可以启动 sbt 在交互模式下运行 `build/sbt`,然后在命令中运行所有构建命令提示。
## 加速编译
经常编译 Spark 的开发人员可能希望加快编译速度; 例如通过使用 Zinc(对于使用 Maven 构建的开发人员)或避免重新编译组件 JAR (对于使用 SBT 构建的开发人员)。 有关如何执行此操作的更多信息,请参阅 [有用的开发工具页面](http://spark.apache.org/developer-tools.html#reducing-build-times)
## 加密文件系统
当在加密文件系统上构建时(例如,如果您的 home 目录是加密的),则 Spark 构建可能会失败,并导致 “Filename too long” 错误。 作为解决方法,在项目 `pom.xml` 中的 `scala-maven-plugin` 的配置参数中添加以下内容:
```
<arg>-Xmax-classfile-name</arg>
<arg>128</arg>
```
`project/SparkBuild.scala` 添加:
```
scalacOptions in Compile ++= Seq("-Xmax-classfile-name", "128"),
```
`sharedSettings` val。 如果您不确定添加这些行的位置,请参阅 [this PR](https://github.com/apache/spark/pull/2883/files)
## IntelliJ IDEA 或 Eclipse
有关设置 IntelliJ IDEA 或 Eclipse 用于 Spark 开发和故障排除的帮助,请参阅 [有用的开发工具页面](http://spark.apache.org/developer-tools.html)
# 运行测试
默认情况下通过 [ScalaTest Maven plugin](http://www.scalatest.org/user_guide/using_the_scalatest_maven_plugin) 进行测试。请注意,测试不应该以 root 用户或者 admin 用户运行。
以下是运行测试的命令示例:
```
./build/mvn test
```
## 使用 SBT 测试
以下是运行测试的命令示例:
```
./build/sbt test
```
## 运行独立测试
有关如何运行独立测试的信息,请参阅 [有用的开发工具页面](http://spark.apache.org/developer-tools.html#running-individual-tests)
## PySpark pip 可安装
如果您正在构建 Spark 以在 Python 环境中使用,并且希望对其进行 pip 安装,那么您将首先需要如上所述构建 Spark JARs 。 然后,您可以构建适合于 setup.py 和 pip 可安装软件包的 sdist 软件包。
```
cd python; python setup.py sdist
```
**注意:** 由于打包要求,您无法直接从 Python 目录中进行 pip 安装,而是必须首先按照上述方式构建 sdist 包。
或者,您还可以使用 –pip 选项运行 make-distribution 。
## 使用 Maven 进行 PySpark 测试
如果您正在构建 PySpark 并希望运行 PySpark 测试,则需要使用 Hive 支持构建 Spark 。
```
./build/mvn -DskipTests clean package -Phive
./python/run-tests
```
run-tests 脚本也可以限于特定的 Python 版本或者特定的模块。
```
./python/run-tests --python-executables=python --modules=pyspark-sql
```
**注意:** 您还可以使用 sbt 构建来运行 Python 测试,只要您使用 Hive 支持构建 Spark 。
## 运行 R 测试
要运行 SparkR 测试,您需要首先安装 [knitr](https://cran.r-project.org/package=knitr), [rmarkdown](https://cran.r-project.org/package=rmarkdown), [testthat](https://cran.r-project.org/package=testthat), [e1071](https://cran.r-project.org/package=e1071) and [survival](https://cran.r-project.org/package=survival) 包:
```
R -e "install.packages(c('knitr', 'rmarkdown', 'testthat', 'e1071', 'survival'), repos='http://cran.us.r-project.org')"
```
您可以使用以下命令只运行 SparkR 测试:
```
./R/run-tests.sh
```
## 运行基于 Docker 的集成测试套装
为了运行 Docker 集成测试,你必须在你的 box 上安装 `docker` engine (引擎)。 有关安装说明,请参见 [Docker 站点](https://docs.docker.com/engine/installation/)。 一旦安装,如果还没有运行 Docker 服务,`docker` service 就需要启动。 在 Linux 上,这可以通过 `sudo service docker start` 来完成。
```
./build/mvn install -DskipTests
./build/mvn test -Pdocker-integration-tests -pl :spark-docker-integration-tests_2.11
```
或者
```
./build/sbt docker-integration-tests/test
```
\ No newline at end of file
# 其它
* [给 Spark 贡献](http://spark.apache.org/contributing.html)
* [第三方项目](http://spark.apache.org/third-party-projects.html): 其它第三方 Spark 项目的支持
\ No newline at end of file
# 外部资源
* [Spark 首页](http://spark.apache.org)
* [Spark 社区](http://spark.apache.org/community.html) 资源, 包括当地的聚会
* [StackOverflow tag `apache-spark`](http://stackoverflow.com/questions/tagged/apache-spark)
* [Mailing Lists](http://spark.apache.org/mailing-lists.html): 在这里询问关于 Spark 的问题
* [AMP Camps](http://ampcamp.berkeley.edu/): 在 UC Berkeley(加州大学伯克利分校)的一系列的训练营中, 它们的特色是讨论和针对关于 Spark, Spark Streaming, Mesos 的练习, 等等。在这里可以免费获取[视频](http://ampcamp.berkeley.edu/6/), [幻灯片](http://ampcamp.berkeley.edu/6/)[练习题](http://ampcamp.berkeley.edu/6/exercises/)
* [Code Examples](http://spark.apache.org/examples.html): 更多`示例`可以在 Spark 的子文件夹中获取 ([Scala](https://github.com/apache/spark/tree/master/examples/src/main/scala/org/apache/spark/examples), [Java](https://github.com/apache/spark/tree/master/examples/src/main/java/org/apache/spark/examples), [Python](https://github.com/apache/spark/tree/master/examples/src/main/python), [R](https://github.com/apache/spark/tree/master/examples/src/main/r))
\ No newline at end of file
# 快速入门
* [使用 Spark Shell 进行交互式分析](#使用-spark-shell-进行交互式分析)
* [基础](#基础)
* [Dataset 上的更多操作](#dataset-上的更多操作)
* [缓存](#缓存)
* [独立的应用](#独立的应用)
* [快速跳转](#快速跳转)
本教程提供了如何使用 Spark 的快速入门介绍。首先通过运行 Spark 交互式的 shell(在 Python 或 Scala 中)来介绍 API, 然后展示如何使用 Java , Scala 和 Python 来编写应用程序。
为了继续阅读本指南, 首先从 [Spark 官网](http://spark.apache.org/downloads.html) 下载 Spark 的发行包。因为我们将不使用 HDFS, 所以你可以下载一个任何 Hadoop 版本的软件包。
请注意, 在 Spark 2.0 之前, Spark 的主要编程接口是弹性分布式数据集(RDD)。 在 Spark 2.0 之后, RDD 被 Dataset 替换, 它是像RDD 一样的 strongly-typed(强类型), 但是在引擎盖下更加优化。 RDD 接口仍然受支持, 您可以在 [RDD 编程指南](rdd-programming-guide.html) 中获得更完整的参考。 但是, 我们强烈建议您切换到使用 Dataset(数据集), 其性能要更优于 RDD。 请参阅 [SQL 编程指南](sql-programming-guide.html) 获取更多有关 Dataset 的信息。
# 使用 Spark Shell 进行交互式分析
## 基础
Spark shell 提供了一种来学习该 API 比较简单的方式, 以及一个强大的来分析数据交互的工具。在 Scala(运行于 Java 虚拟机之上, 并能很好的调用已存在的 Java 类库)或者 Python 中它是可用的。通过在 Spark 目录中运行以下的命令来启动它:
```
./bin/spark-shell
```
Spark 的主要抽象是一个称为 Dataset 的分布式的 item 集合。Datasets 可以从 Hadoop 的 InputFormats(例如 HDFS文件)或者通过其它的 Datasets 转换来创建。让我们从 Spark 源目录中的 README 文件来创建一个新的 Dataset:
```
scala> val textFile = spark.read.textFile("README.md")
textFile: org.apache.spark.sql.Dataset[String] = [value: string]
```
您可以直接从 Dataset 中获取 values(值), 通过调用一些 actions(动作), 或者 transform(转换)Dataset 以获得一个新的。更多细节, 请参阅 _[API doc](api/scala/index.html#org.apache.spark.sql.Dataset)_。
```
scala> textFile.count() // Number of items in this Dataset
res0: Long = 126 // May be different from yours as README.md will change over time, similar to other outputs
scala> textFile.first() // First item in this Dataset
res1: String = # Apache Spark
```
现在让我们 transform 这个 Dataset 以获得一个新的。我们调用 `filter` 以返回一个新的 Dataset, 它是文件中的 items 的一个子集。
```
scala> val linesWithSpark = textFile.filter(line => line.contains("Spark"))
linesWithSpark: org.apache.spark.sql.Dataset[String] = [value: string]
```
我们可以链式操作 transformation(转换)和 action(动作):
```
scala> textFile.filter(line => line.contains("Spark")).count() // How many lines contain "Spark"?
res3: Long = 15
```
```
./bin/pyspark
```
Spark’s primary abstraction is a distributed collection of items called a Dataset. Datasets can be created from Hadoop InputFormats (such as HDFS files) or by transforming other Datasets. Due to Python’s dynamic nature, we don’t need the Dataset to be strongly-typed in Python. As a result, all Datasets in Python are Dataset[Row], and we call it `DataFrame` to be consistent with the data frame concept in Pandas and R. Let’s make a new DataFrame from the text of the README file in the Spark source directory:
```
>>> textFile = spark.read.text("README.md")
```
You can get values from DataFrame directly, by calling some actions, or transform the DataFrame to get a new one. For more details, please read the _[API doc](api/python/index.html#pyspark.sql.DataFrame)_.
```
>>> textFile.count() # Number of rows in this DataFrame
126
>>> textFile.first() # First row in this DataFrame
Row(value=u'# Apache Spark')
```
Now let’s transform this DataFrame to a new one. We call `filter` to return a new DataFrame with a subset of the lines in the file.
```
>>> linesWithSpark = textFile.filter(textFile.value.contains("Spark"))
```
We can chain together transformations and actions:
```
>>> textFile.filter(textFile.value.contains("Spark")).count() # How many lines contain "Spark"?
15
```
## Dataset 上的更多操作
Dataset actions(操作)和 transformations(转换)可以用于更复杂的计算。例如, 统计出现次数最多的行 :
```
scala> textFile.map(line => line.split(" ").size).reduce((a, b) => if (a > b) a else b)
res4: Long = 15
```
第一个 map 操作创建一个新的 Dataset, 将一行数据 map 为一个整型值。在 Dataset 上调用 `reduce` 来找到最大的行计数。参数 `map``reduce` 是 Scala 函数(closures), 并且可以使用 Scala/Java 库的任何语言特性。例如, 我们可以很容易地调用函数声明, 我们将定义一个 max 函数来使代码更易于理解 :
```
scala> import java.lang.Math
import java.lang.Math
scala> textFile.map(line => line.split(" ").size).reduce((a, b) => Math.max(a, b))
res5: Int = 15
```
一种常见的数据流模式是被 Hadoop 所推广的 MapReduce。Spark 可以很容易实现 MapReduce:
```
scala> val wordCounts = textFile.flatMap(line => line.split(" ")).groupByKey(identity).count()
wordCounts: org.apache.spark.sql.Dataset[(String, Long)] = [value: string, count(1): bigint]
```
在这里, 我们调用了 `flatMap` 以 transform 一个 lines 的 Dataset 为一个 words 的 Dataset, 然后结合 `groupByKey``count` 来计算文件中每个单词的 counts 作为一个 (String, Long) 的 Dataset pairs。要在 shell 中收集 word counts, 我们可以调用 `collect`:
```
scala> wordCounts.collect()
res6: Array[(String, Int)] = Array((means,1), (under,2), (this,3), (Because,1), (Python,2), (agree,1), (cluster.,1), ...)
```
```
>>> from pyspark.sql.functions import *
>>> textFile.select(size(split(textFile.value, "\s+")).name("numWords")).agg(max(col("numWords"))).collect()
[Row(max(numWords)=15)]
```
This first maps a line to an integer value and aliases it as “numWords”, creating a new DataFrame. `agg` is called on that DataFrame to find the largest word count. The arguments to `select` and `agg` are both _[Column](api/python/index.html#pyspark.sql.Column)_, we can use `df.colName` to get a column from a DataFrame. We can also import pyspark.sql.functions, which provides a lot of convenient functions to build a new Column from an old one.
One common data flow pattern is MapReduce, as popularized by Hadoop. Spark can implement MapReduce flows easily:
```
>>> wordCounts = textFile.select(explode(split(textFile.value, "\s+")).as("word")).groupBy("word").count()
```
Here, we use the `explode` function in `select`, to transfrom a Dataset of lines to a Dataset of words, and then combine `groupBy` and `count` to compute the per-word counts in the file as a DataFrame of 2 columns: “word” and “count”. To collect the word counts in our shell, we can call `collect`:
```
>>> wordCounts.collect()
[Row(word=u'online', count=1), Row(word=u'graphs', count=1), ...]
```
## 缓存
Spark 还支持 Pulling(拉取)数据集到一个群集范围的内存缓存中。例如当查询一个小的 “hot” 数据集或运行一个像 PageRANK 这样的迭代算法时, 在数据被重复访问时是非常高效的。举一个简单的例子, 让我们标记我们的 `linesWithSpark` 数据集到缓存中:
```
scala> linesWithSpark.cache()
res7: linesWithSpark.type = [value: string]
scala> linesWithSpark.count()
res8: Long = 15
scala> linesWithSpark.count()
res9: Long = 15
```
使用 Spark 来探索和缓存一个 100 行的文本文件看起来比较愚蠢。有趣的是, 即使在他们跨越几十或者几百个节点时, 这些相同的函数也可以用于非常大的数据集。您也可以像 [编程指南](rdd-programming-guide.html#using-the-shell). 中描述的一样通过连接 `bin/spark-shell` 到集群中, 使用交互式的方式来做这件事情。
```
>>> linesWithSpark.cache()
>>> linesWithSpark.count()
15
>>> linesWithSpark.count()
15
```
It may seem silly to use Spark to explore and cache a 100-line text file. The interesting part is that these same functions can be used on very large data sets, even when they are striped across tens or hundreds of nodes. You can also do this interactively by connecting `bin/pyspark` to a cluster, as described in the [RDD programming guide](rdd-programming-guide.html#using-the-shell).
# 独立的应用
假设我们希望使用 Spark API 来创建一个独立的应用程序。我们在 Scala(SBT), Java(Maven)和 Python 中练习一个简单应用程序。
我们将在 Scala 中创建一个非常简单的 Spark 应用程序 - 很简单的, 事实上, 它名为 `SimpleApp.scala`:
```
/* SimpleApp.scala */
import org.apache.spark.sql.SparkSession
object SimpleApp {
def main(args: Array[String]) {
val logFile = "YOUR_SPARK_HOME/README.md" // Should be some file on your system
val spark = SparkSession.builder.appName("Simple Application").getOrCreate()
val logData = spark.read.textFile(logFile).cache()
val numAs = logData.filter(line => line.contains("a")).count()
val numBs = logData.filter(line => line.contains("b")).count()
println(s"Lines with a: $numAs, Lines with b: $numBs")
spark.stop()
}
}
```
注意, 这个应用程序我们应该定义一个 `main()` 方法而不是去扩展 `scala.App`。使用 `scala.App` 的子类可能不会正常运行。
该程序仅仅统计了 Spark README 文件中每一行包含 ‘a’ 的数量和包含 ‘b’ 的数量。注意, 您需要将 YOUR_SPARK_HOME 替换为您 Spark 安装的位置。不像先前使用 spark shell 操作的示例, 它们初始化了它们自己的 SparkContext, 我们初始化了一个 SparkContext 作为应用程序的一部分。
我们调用 `SparkSession.builder` 以构造一个 [[SparkSession]], 然后设置 application name(应用名称), 最终调用 `getOrCreate` 以获得 [[SparkSession]] 实例。
我们的应用依赖了 Spark API, 所以我们将包含一个名为 `build.sbt` 的 sbt 配置文件, 它描述了 Spark 的依赖。该文件也会添加一个 Spark 依赖的 repository:
```
name := "Simple Project"
version := "1.0"
scalaVersion := "2.11.8"
libraryDependencies += "org.apache.spark" %% "spark-sql" % "2.2.0"
```
为了让 sbt 正常的运行, 我们需要根据经典的目录结构来布局 `SimpleApp.scala``build.sbt` 文件。在成功后, 我们可以创建一个包含应用程序代码的 JAR 包, 然后使用 `spark-submit` 脚本来运行我们的程序。
```
# Your directory layout should look like this
$ find .
.
./build.sbt
./src
./src/main
./src/main/scala
./src/main/scala/SimpleApp.scala
# Package a jar containing your application
$ sbt package
...
[info] Packaging {..}/{..}/target/scala-2.11/simple-project_2.11-1.0.jar
# Use spark-submit to run your application
$ YOUR_SPARK_HOME/bin/spark-submit \
--class "SimpleApp" \
--master local[4] \
target/scala-2.11/simple-project_2.11-1.0.jar
...
Lines with a: 46, Lines with b: 23
```
这个例子使用Maven来编译成一个jar应用程序,其他的构建系统(如Ant、Gradle,译者注)也可以。
我们会创建一个非常简单的Spark应用,`SimpleApp.java`:
```
/* SimpleApp.java */
import org.apache.spark.sql.SparkSession;
public class SimpleApp {
public static void main(String[] args) {
String logFile = "YOUR_SPARK_HOME/README.md"; // Should be some file on your system
SparkSession spark = SparkSession.builder().appName("Simple Application").getOrCreate();
Dataset<String> logData = spark.read.textFile(logFile).cache();
long numAs = logData.filter(s -> s.contains("a")).count();
long numBs = logData.filter(s -> s.contains("b")).count();
System.out.println("Lines with a: " + numAs + ", lines with b: " + numBs);
spark.stop();
}
}
```
这个程序计算Spark README文档中包含字母’a’和字母’b’的行数。注意把YOUR_SPARK_HOME修改成你的Spark的安装目录。 跟之前的Spark shell不同,我们需要初始化SparkSession。
把Spark依赖添加到Maven的`pom.xml`文件里。 注意Spark的artifacts使用Scala版本进行标记。
```
<project>
<groupId>edu.berkeley</groupId>
<artifactId>simple-project</artifactId>
<modelVersion>4.0.0</modelVersion>
<name>Simple Project</name>
<packaging>jar</packaging>
<version>1.0</version>
<dependencies>
<dependency> <!-- Spark dependency -->
<groupId>org.apache.spark</groupId>
<artifactId>spark-sql_2.11</artifactId>
<version>2.2.0</version>
</dependency>
</dependencies>
</project>
```
我们按照Maven经典的目录结构组织这些文件:
```
$ find .
./pom.xml
./src
./src/main
./src/main/java
./src/main/java/SimpleApp.java
```
现在我们用Maven打包这个应用,然后用`./bin/spark-submit`执行它。
```
# 打包包含应用程序的JAR
$ mvn package
...
[INFO] Building jar: {..}/{..}/target/simple-project-1.0.jar
# 用spark-submit来运行程序
$ YOUR_SPARK_HOME/bin/spark-submit \
--class "SimpleApp" \
--master local[4] \
target/simple-project-1.0.jar
...
Lines with a: 46, Lines with b: 23
```
Now we will show how to write an application using the Python API (PySpark).
As an example, we’ll create a simple Spark application, `SimpleApp.py`:
```
"""SimpleApp.py"""
from pyspark.sql import SparkSession
logFile = "YOUR_SPARK_HOME/README.md" # Should be some file on your system
spark = SparkSession.builder().appName(appName).master(master).getOrCreate()
logData = spark.read.text(logFile).cache()
numAs = logData.filter(logData.value.contains('a')).count()
numBs = logData.filter(logData.value.contains('b')).count()
print("Lines with a: %i, lines with b: %i" % (numAs, numBs))
spark.stop()
```
This program just counts the number of lines containing ‘a’ and the number containing ‘b’ in a text file. Note that you’ll need to replace YOUR_SPARK_HOME with the location where Spark is installed. As with the Scala and Java examples, we use a SparkSession to create Datasets. For applications that use custom classes or third-party libraries, we can also add code dependencies to `spark-submit` through its `--py-files` argument by packaging them into a .zip file (see `spark-submit --help` for details). `SimpleApp` is simple enough that we do not need to specify any code dependencies.
We can run this application using the `bin/spark-submit` script:
```
# Use spark-submit to run your application
$ YOUR_SPARK_HOME/bin/spark-submit \
--master local[4] \
SimpleApp.py
...
Lines with a: 46, Lines with b: 23
```
# 快速跳转
恭喜您成功的运行了您的第一个 Spark 应用程序!
* 更多 API 的深入概述, 从 [RDD programming guide](rdd-programming-guide.html)[SQL programming guide](sql-programming-guide.html) 这里开始, 或者看看 “编程指南” 菜单中的其它组件。
* 为了在集群上运行应用程序, 请前往 [deployment overview](cluster-overview.html).
* 最后, 在 Spark 的 `examples` 目录中包含了一些 ([Scala](https://github.com/apache/spark/tree/master/examples/src/main/scala/org/apache/spark/examples), [Java](https://github.com/apache/spark/tree/master/examples/src/main/java/org/apache/spark/examples), [Python](https://github.com/apache/spark/tree/master/examples/src/main/python), [R](https://github.com/apache/spark/tree/master/examples/src/main/r)) 示例。您可以按照如下方式来运行它们:
```
# 针对 Scala 和 Java, 使用 run-example:
./bin/run-example SparkPi
# 针对 Python 示例, 直接使用 spark-submit:
./bin/spark-submit examples/src/main/python/pi.py
# 针对 R 示例, 直接使用 spark-submit:
./bin/spark-submit examples/src/main/r/dataframe.R
```
# Spark 官方文档中文版翻译进度
## 前言
感谢大家默默的无私付出,感谢 [ApacheCN](htttp://www.apachecn.org) 让我们聚在一起奋斗, 才有了这份中文文档,我们一直在努力!~~~
网址: [http://spark.apachecn.org/docs/cn/2.2.0](http://spark.apachecn.org/docs/cn/2.2.0/)
github: [https://github.com/apachecn/spark-doc-zh](https://github.com/apachecn/spark-doc-zh)
贡献者: [https://github.com/apachecn/spark-doc-zh#贡献者](https://github.com/apachecn/spark-doc-zh#贡献者)
建议反馈: [https://github.com/apachecn/spark-doc-zh#联系方式](https://github.com/apachecn/spark-doc-zh#联系方式)
## Apache Spark 2.2.0 官方文档中文版翻译进度
* 2017-09-20: 校验 structured-streaming-kafka-integration.md 其中有问题的地方。
* 2017-09-14: 修改 sql-programming-guide.md 中其它翻译有问题的地方, 更多细节请看:[https://github.com/apachecn/spark-doc-zh/issues/95](https://github.com/apachecn/spark-doc-zh/issues/95)
* 2017-09-13: 修改 sql-programming-guide.md 中的`写作``写操作`, 英文原文为`writing`. 更多细节请看[https://github.com/apachecn/spark-doc-zh/issues/95](https://github.com/apachecn/spark-doc-zh/issues/95)
* 2017-08-29: 修改 index.md 中的语法问题.
* 2017-08-23: 修复 sql-programming-guide.md 中格式错乱的 BUG.
* 2017-08-14: 修改 index.md 和 tuning.md 中不正确的地方.
* 2017-08-08: 修改 index.md 中 API 文档失效的链接,直接指向官网,并且修改页面底部展示的风格.
* 2017-08-04: 增加[Spark Sql](http://spark.apachecn.org/docs/cn/2.2.0/sql-programming-guide.html)的文档翻译部分(100%).
* 2017-08-03: 增加[Spark Streaming](http://spark.apachecn.org/docs/cn/2.2.0/streaming-programming-guide.html)的文档翻译部分(100%).
* 2017-07-25:[Apache Spark 2.2.0 官方文档中文版](http://spark.apachecn.org/docs/cn/2.2.0/)发布(翻译进度 80%), 维护网址:[http://spark.apachecn.org/docs/cn/2.2.0/](http://spark.apachecn.org/docs/cn/2.2.0/)
| 是否完成 | 完成百分比 | 任务名称 | Markdown | 工期 | 开始时间 | 结束时间 | 贡献者 | 备注 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 否 | 98% | ◢ Apache Spark 2.2.0 官方文档中文版翻译 | | 14 天 | 2017-07-18 | 2017-07-31 | | |
| 是 | 100% |     Overview | index.md | 1 天 | 2017-07-18 | 2017-07-18 | [@wangyangting](https://github.com/wangyangting)(那伊抹微笑) | |
| 否 | 98% |     ◢ Spark Programming Guide | | | | | | |
| 是 | 100% |         Quick Start | quick-start.md | 1 天 | 2017-07-19 | 2017-07-19 | [@wangyangting](https://github.com/wangyangting)(那伊抹微笑) | |
| 是 | 100% |         Spark Programming Guide | rdd-programming-guide.md | 1 天 | 2017-07-21 | 2017-07-21 | [@wangyangting](https://github.com/wangyangting)(那伊抹微笑) | |
| 是 | 100% |         Spark streaming | streaming-programming-guide.md | 1 天 | 2017-08-03 | 2017-08-03 | [@wangyangting](https://github.com/wangyangting)(那伊抹微笑)
[@jiangzhonglian](https://github.com/jiangzhonglian)(片刻)
[@chenyyx](https://github.com/chenyyx)(Joy yx) | |
| 否 | 98% |         Data Frames, Datasets and SQL | sql-programming-guide.md | 1 天 | 2017-07-18 | | [@qinchaofeng](https://github.com/qinchaofeng)(qinchaofeng)
[@chenyyx](https://github.com/chenyyx)(Joy yx)
[@jiangzhonglian](https://github.com/jiangzhonglian)(片刻)
[@wangyangting](https://github.com/wangyangting)(那伊抹微笑) | |
| 是 | 100% |         Structured Streaming | structured-streaming-programming-guide.md | 1 天 | 2017-07-21 | 2017-07-21 | [@chenyyx](https://github.com/chenyyx)(Joy yx) | |
| 是 | 100% |         Mlib(Machine Learning) | ml-guide.md | 1 天 | 2017-07-20 | 2017-07-20 | [@chenyyx](https://github.com/chenyyx)(Joy yx) | |
| 是 | 100% |         GraphX(Graph Processing) | graphx-programming-guide.md | 1 天 | 2017-07-21 | 2017-07-21 | [@jiangzhonglian](https://github.com/jiangzhonglian)(片刻) | |
| 是 | 100% |         SparkR(R on Spark) | sparkr.md | 1 天 | 2017-07-24 | 2017-07-24 | [@kris37](https://github.com/kris37)(kris37)
[@wangyangting](https://github.com/wangyangting)(那伊抹微笑) | |
| 是 | 100% |     ◢ Deploying | | | | | | |
| 是 | 100% |         Overview | cluster-overview.md | 1 天 | 2017-07-20 | 2017-07-20 | [@huangtianan](https://github.com/huangtianan)(huangtianan) | |
| 是 | 100% |         Submitting Applications | submitting-applications.md | 1 天 | 2017-07-20 | 2017-07-20 | [@sehriff](https://github.com/sehriff)(sehriff) | |
| 是 | 100% |         Spark Standalone | spark-standalone.md | 1 天 | 2017-07-19 | 2017-07-19 | [@chenyyx](https://github.com/chenyyx)(Joy yx) | |
| 是 | 100% |         Mesos | running-on-mesos.md | 1 天 | 2017-07-19 | 2017-07-19 | [@chenyyx](https://github.com/chenyyx)(Joy yx) | |
| 是 | 100% |         YARN | running-on-yarn.md | 1 天 | 2017-07-19 | 2017-07-19 | [@wangyangting](https://github.com/wangyangting)(那伊抹微笑) | |
| 是 | 100% |     ◢ More | | | | | | |
| 是 | 100% |         Configuration | configuration.md | 1 天 | 2017-07-25 | 2017-07-25 | [@chenyyx](https://github.com/chenyyx)(Joy yx)
[@jiangzhonglian](https://github.com/jiangzhonglian)(片刻) | |
| 是 | 100% |         Monitoring | monitoring.md | 1 天 | 2017-07-19 | 2017-07-19 | [@jiangzhonglian](https://github.com/jiangzhonglian)(片刻) | |
| 是 | 100% |         Tuning Guide | tuning.md | 1 天 | 2017-07-20 | 2017-07-20 | [@jiangzhonglian](https://github.com/jiangzhonglian)(片刻) | |
| 是 | 100% |         Job Scheduling | job-scheduling.md | 1 天 | 2017-07-27 | 2017-07-27 | [@stealthsMrs](https://github.com/stealthsMrs)(stealthsMrs) | |
| 是 | 100% |         Security | security.md | 1 天 | 2017-07-19 | 2017-07-19 | [@wangyangting](https://github.com/wangyangting)(那伊抹微笑) | |
| 是 | 100% |         Hardware Provisioning | hardware-provisioning.md | 1 天 | 2017-07-24 | 2017-07-24 | [@huangtianan](https://github.com/huangtianan)(huangtianan) | |
| 是 | 100% |         Building Spark | building-spark.md | 1 天 | 2017-07-20 | 2017-07-20 | [@chenyyx](https://github.com/chenyyx)(Joy yx) | |
\ No newline at end of file
此差异已折叠。
# 构建在 Spark 之上的模块
\ No newline at end of file
此差异已折叠。
此差异已折叠。
# MLlib
\ No newline at end of file
此差异已折叠。
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta charset="UTF-8">
<link rel="stylesheet" href="//unpkg.com/docsify/themes/vue.css">
<!-- google ads -->
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- baidu stats -->
<script>
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?3cf78c4e16d1962985911db962821405";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
<!-- google webmaster -->
<meta name="google-site-verification" content="pyo9N70ZWyh8JB43bIu633mhxesJ1IcwWCZlM3jUfFo" />
</head>
<body>
<div id="app">now loading...</div>
<script id="footer" type="text/xml">
<hr/>
<div align="center">
<p><a href="http://www.apachecn.org/" target="_blank"><font face="KaiTi" size="6" color="red">我们一直在努力</font></a><p>
<p><a href="https://github.com/apachecn/spark-doc-zh/" target="_blank">apachecn/spark-doc-zh</a></p>
<p><iframe align="middle" src="https://ghbtns.com/github-btn.html?user=apachecn&repo=spark-doc-zh&type=watch&count=true&v=2" frameborder="0" scrolling="0" width="100px" height="25px"></iframe>
<iframe align="middle" src="https://ghbtns.com/github-btn.html?user=apachecn&repo=spark-doc-zh&type=star&count=true" frameborder="0" scrolling="0" width="100px" height="25px"></iframe>
<iframe align="middle" src="https://ghbtns.com/github-btn.html?user=apachecn&repo=spark-doc-zh&type=fork&count=true" frameborder="0" scrolling="0" width="100px" height="25px"></iframe>
<a target="_blank" href="//shang.qq.com/wpa/qunwpa?idkey=bcee938030cc9e1552deb3bd9617bbbf62d3ec1647e4b60d9cd6b6e8f78ddc03"><img border="0" src="//pub.idqqimg.com/wpa/images/group.png" alt="ML | ApacheCN" title="ML | ApacheCN"></a></p>
<div style="text-align:center;margin:0 0 10.5px;">
<ins class="adsbygoogle"
style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-3565452474788507"
data-ad-slot="2543897000"></ins>
</div>
</div>
</script>
<script>
window.docsPlugin = function(hook) {
var footer = document.querySelector('#footer').innerHTML
hook.afterEach(function(html) {
return html + footer
})
hook.doneEach(function() {
(adsbygoogle = window.adsbygoogle || []).push({})
})
}
window.$docsify = {
loadSidebar: 'SUMMARY.md',
name: 'Spark 2.2.0 中文文档',
auto2top: true,
themeColor: '#ff7043',
repo: 'apachecn/spark-doc-zh',
plugins: [window.docsPlugin],
}
</script>
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
</body>
</html>
\ No newline at end of file
git add -A
git commit -am "$(date "+%Y-%m-%d %H:%M:%S")"
git push
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册