From 58680e4a600c704a5a687f5d1ee56ca0fee6c751 Mon Sep 17 00:00:00 2001 From: tys1998 Date: Sun, 7 Apr 2019 15:16:46 +0800 Subject: [PATCH] =?UTF-8?q?":=20"=20to=20"=EF=BC=9A"=20and=20"=20=EF=BC=9A?= =?UTF-8?q?"=20to=20"=EF=BC=9A"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CONTRIBUTING.md | 24 ++++++++++---------- README.md | 6 ++--- docs/1.md | 2 +- docs/13.md | 12 +++++----- docs/15.md | 12 +++++----- docs/16.md | 16 ++++++------- docs/17.md | 6 ++--- docs/18.md | 4 ++-- docs/20.md | 26 ++++++++++----------- docs/21.md | 28 +++++++++++------------ docs/22.md | 4 ++-- docs/23.md | 14 ++++++------ docs/25.md | 2 +- docs/28.md | 2 +- docs/29.md | 6 ++--- docs/30.md | 28 +++++++++++------------ docs/4.md | 20 ++++++++--------- docs/6.md | 58 +++++++++++++++++++++++------------------------ docs/7.md | 34 ++++++++++++++-------------- docs/9.md | 8 +++---- docs/paper.md | 60 ++++++++++++++++++++++++------------------------- 21 files changed, 186 insertions(+), 186 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 924d463..b25ff4d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,24 +7,24 @@ ## 参与翻译 & 发现错误 1. 在 github 上 fork 该 repository. -2. 翻译 doc/zh 下面的 md 文件即可, 例如, index.md. -3. 然后, 在你的 github 发起 New pull request 请求. -4. 工具使用, 可参考下面的内容. +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). +简易的使用指南请参阅:[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 方面经验稍微丰富点. +* 翻译:负责文章内容的翻译. +* 校验:负责文章内容的校验,比如格式,正确度之类的. +* 负责人:负责整个 Projcet,不至于让该 Project 成为垃圾项目,需要在 Spark 方面经验稍微丰富点. -有兴趣参与的朋友, 可以看看最后的联系方式. +有兴趣参与的朋友,可以看看最后的联系方式. diff --git a/README.md b/README.md index fbbf117..91218ce 100644 --- a/README.md +++ b/README.md @@ -41,13 +41,13 @@ Apache Spark? 是一个快速的,用于海量数据处理的通用引擎. ### 2.0.2 -请参阅: [http://cwiki.apachecn.org/pages/viewpage.action?pageId=2887089](http://cwiki.apachecn.org/pages/viewpage.action?pageId=2887089) +请参阅:[http://cwiki.apachecn.org/pages/viewpage.action?pageId=2887089](http://cwiki.apachecn.org/pages/viewpage.action?pageId=2887089) ## 联系方式 有任何建议反馈,或想参与文档翻译,麻烦联系下面的企鹅: -* 企鹅: 1042658081 +* 企鹅:1042658081 ## 赞助我们 @@ -60,7 +60,7 @@ GPL-3.0 © [ApacheCN](https://github.com/apachecn) ## Organization -* ApacheCN 组织资源: +* ApacheCN 组织资源: > 欢迎任何人参与和完善:一个人可以走的很快,但是一群人却可以走的更远 diff --git a/docs/1.md b/docs/1.md index 664da65..1b79eb4 100644 --- a/docs/1.md +++ b/docs/1.md @@ -58,6 +58,6 @@ R 中也提供了应用示例。例如, 该 Spark [集群模式概述](cluster-overview.html) 说明了在集群上运行的主要的概念。Spark 既可以独立运行,也可以在一些现有的 Cluster Manager(集群管理器)上运行。它当前提供了几种用于部署的选项: -* [Standalone Deploy Mode](spark-standalone.html): 在私有集群上部署 Spark 最简单的方式 +* [Standalone Deploy Mode](spark-standalone.html):在私有集群上部署 Spark 最简单的方式 * [Apache Mesos](running-on-mesos.html) * [Hadoop YARN](running-on-yarn.html) diff --git a/docs/13.md b/docs/13.md index ba62392..6973f02 100644 --- a/docs/13.md +++ b/docs/13.md @@ -29,12 +29,12 @@ 一些常用的 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 方法的参数,如果有的话。 +* `--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)的应用程序。 diff --git a/docs/15.md b/docs/15.md index 9cd7808..fcfdb2c 100644 --- a/docs/15.md +++ b/docs/15.md @@ -29,7 +29,7 @@ Spark 除了运行在 Mesos 或者 YARN 上以外,Spark 还提供了一个简 一旦启动,master 将会为自己打印出一个 `spark://HOST:PORT` URL,您可以使用它来连接 workers,或者像传递 “master” 参数一样传递到 `SparkContext`。您在 master 的web UI 上也会找到这个 URL,默认情况下是 [http://localhost:8080](http://localhost:8080)。 -类似地,您可以启动一个或多个 workers 并且通过下面的代码连接到 master : +类似地,您可以启动一个或多个 workers 并且通过下面的代码连接到 master: ``` ./sbin/start-slave.sh @@ -37,14 +37,14 @@ Spark 除了运行在 Mesos 或者 YARN 上以外,Spark 还提供了一个简 在您启动一个 worker 之后,就可以通过 master 的 web UI ( 默认情况下是 [http://localhost:8080](http://localhost:8080))查看到了。您可以看到列出的新的 node (节点),以及其 CPU 的数量和数量(为操作系统留下了 1 GB 的空间)。 -最后,下面的配置选项可以传递给 master 和 worker : +最后,下面的配置选项可以传递给 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) | +| `-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 上可用 | @@ -79,7 +79,7 @@ Spark 除了运行在 Mesos 或者 YARN 上以外,Spark 还提供了一个简 | `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_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) | @@ -216,7 +216,7 @@ ZooKeeper 是生产级别的高可用性的最佳方法,但是如果您只是 **配置** -为了启用此恢复模式,你可以使用以下配置在 spark-env 中设置 SPARK_DAEMON_JAVA_OPTS : +为了启用此恢复模式,你可以使用以下配置在 spark-env 中设置 SPARK_DAEMON_JAVA_OPTS: | System property(系统属性) | Meaning(含义) | | --- | --- | diff --git a/docs/16.md b/docs/16.md index e7d1300..43a747b 100644 --- a/docs/16.md +++ b/docs/16.md @@ -58,7 +58,7 @@ Spark 2.2.0 专门为 Mesos 1.0.0 或更新的版本并且不需要 Mesos 的任 Apache Mesos 只发布了源码的发行版本,而不是 binary packages (二进制包)。但是其他的第三方项目发布了 binary releases (二进制发行版本),可能对设置 Mesos 有帮助。 -其中之一是 Mesosphere。使用 Mesosphere 提供的 binary releases (二进制发行版本)安装 Mesos : +其中之一是 Mesosphere。使用 Mesosphere 提供的 binary releases (二进制发行版本)安装 Mesos: 1. 从 [下载页面](http://mesosphere.io/downloads/) 下载 Mesos 安装包 2. 按照他们的说明进行安装和配置 @@ -167,15 +167,15 @@ Spark on Mesos 还支持 cluster mode (集群模式),其中 driver 在集 # Mesos 运行模式 -Spark 可以以两种模式运行 Mesos : “coarse-grained(粗粒度)”(默认) 和 “fine-grained(细粒度)”(不推荐)。 +Spark 可以以两种模式运行 Mesos: “coarse-grained(粗粒度)”(默认) 和 “fine-grained(细粒度)”(不推荐)。 ## Coarse-Grained(粗粒度) 在 “coarse-grained(粗粒度) 模式下,每个 Spark 执行器都作为单个 Mesos 任务运行。Spark 执行器的大小是根据下面的配置变量确定的: -* Executor memory(执行器内存): `spark.executor.memory` -* Executor cores(执行器核): `spark.executor.cores` -* Number of executors(执行器数量): `spark.cores.max`/`spark.executor.cores` +* Executor memory(执行器内存):`spark.executor.memory` +* Executor cores(执行器核):`spark.executor.cores` +* Number of executors(执行器数量):`spark.cores.max`/`spark.executor.cores` 请参阅 [Spark 配置](configuration.html) 页面来了解细节和默认值。 @@ -239,7 +239,7 @@ Mesos 仅支持使用粗粒度模式的动态分配,这可以基于应用程 要使用的外部 Shuffle 服务是 Mesos Shuffle 服务。它在 Shuffle 服务之上提供 shuffle 数据清理功能,因为 Mesos 尚不支持通知另一个框架的终止。要启动它,在所有从节点上运 `$SPARK_HOME/sbin/start-mesos-shuffle-service.sh`,并将 `spark.shuffle.service.enabled` 设置为`true`。 -这也可以通过 Marathon,使用唯一的主机约束和以下命令实现 : `bin/spark-class org.apache.spark.deploy.mesos.MesosExternalShuffleService`。 +这也可以通过 Marathon,使用唯一的主机约束和以下命令实现:`bin/spark-class org.apache.spark.deploy.mesos.MesosExternalShuffleService`。 # 配置 @@ -298,13 +298,13 @@ key1=val1,key2=val2,key3=val3 在调试中可以看的地方: -* Mesos Master 的端口 : 5050 +* Mesos Master 的端口:5050 * Slaves 应该出现在 Slaves 那一栏 * Spark 应用应该出现在框架那一栏 * 任务应该出现在在一个框架的详情 * 检查失败任务的 sandbox 的 stdout 和 stderr * Mesos 的日志 - * Master 和 Slave 的日志默认在 : `/var/log/mesos` 目录 + * Master 和 Slave 的日志默认在:`/var/log/mesos` 目录 常见的陷阱: diff --git a/docs/17.md b/docs/17.md index d1a3fb4..f4ecdc7 100644 --- a/docs/17.md +++ b/docs/17.md @@ -79,7 +79,7 @@ yarn logs -applicationId * 使用 `spark-submit` 上传一个自定义的 `log4j.properties`,通过将 spark-submit 添加到要与应用程序一起上传的文件的 –files 列表中。 * add `-Dlog4j.configuration=<location of configuration file>` to `spark.driver.extraJavaOptions` (for the driver) or `spark.executor.extraJavaOptions` (for executors). Note that if using a file, the `file:` protocol should be explicitly provided, and the file needs to exist locally on all the nodes. -* 添加 `-Dlog4j.configuration=<配置文件的位置>` 到 `spark.driver.extraJavaOptions`(对于驱动程序)或者 containers (对于执行者)。请注意,如果使用文件,文件: 协议(protocol )应该被显式提供,并且该文件需要在所有节点的本地存在。 +* 添加 `-Dlog4j.configuration=<配置文件的位置>` 到 `spark.driver.extraJavaOptions`(对于驱动程序)或者 containers (对于执行者)。请注意,如果使用文件,文件:协议(protocol )应该被显式提供,并且该文件需要在所有节点的本地存在。 * 更新 `$SPARK_CONF_DIR/log4j.properties` 文件,并且它将与其他配置一起自动上传。请注意,如果指定了多个选项,其他 2 个选项的优先级高于此选项。 请注意,对于第一个选项,executors 和 application master 将共享相同的 log4j 配置,这当它们在同一个节点上运行的时候,可能会导致问题(例如,试图写入相同的日志文件)。 @@ -92,7 +92,7 @@ To use a custom metrics.properties for the application master and executors, upd #### Spark 属性 - # 重要提示 - core request 在调度决策中是否得到执行取决于使用的调度程序及其配置方式。- 在 `cluster 集群` 模式中,Spark executors 和 Spark dirver 使用的本地目录是为 YARN(Hadoop YARN 配置 `yarn.nodemanager.local-dirs`)配置的本地目录。如果用户指定 `spark.local.dir`,它将被忽略。在 `client 客户端` 模式下,Spark executors 将使用为 YARN 配置的本地目录,Spark dirver 将使用 `spark.local.dir` 中定义的目录。这是因为 Spark drivers 不在 YARN cluster 的 `client ` 模式中运行,仅仅 Spark 的 executors 会这样做。- `--files` 和 `--archives` 支持用 # 指定文件名,与 Hadoop 相似。例如您可以指定: `--files localtest.txt#appSees.txt` 然后就会上传本地名为 `localtest.txt` 的文件到 HDFS 中去,但是会通过名称 `appSees.txt` 来链接,当你的应用程序在 YARN 上运行时,你应该使用名称 `appSees.txt` 来引用它。- The `--jars` 选项允许你在 `cluster 集群` 模式下使用本地文件时运行 `SparkContext.addJar` 函数。如果你使用 HDFS,HTTP,HTTPS 或 FTP 文件,则不需要使用它。# 在安全集群中运行 如 [security](security.html) 所讲的,Kerberos 被应用在安全的 Hadoop 集群中去验证与服务和客户端相关联的 principals。这允许客户端请求这些已验证的服务; 向授权的 principals 授予请求服务的权利。Hadoop 服务发出 *hadoop tokens* 去授权访问服务和数据。客户端必须首先获取它们将要访问的服务的 tokens,当启动应用程序时,将它和应用程序一起发送到 YAYN 集群中。如果 Spark 应用程序与其它任何的 Hadoop 文件系统(例如 hdfs,webhdfs,等等),HDFS,HBase 和 Hive 进行交互,它必须使用启动应用程序的用户的 Kerberos 凭据获取相关 tokens,也就是说身份将成为已启动的 Spark 应用程序的 principal。这通常在启动时完成 : 在安全集群中,Spark 将自动为集群的 HDFS 文件系统获取 tokens,也可能为 HBase 和 Hive 获取。如果 HBase 在 classpath 中,HBase token 是可以获取的,HBase 配置声明应用程序是安全的(即 `hbase-site.xml` 将 `hbase.security.authentication` 设置为 `kerberos`),并且 `spark.yarn.security.tokens.hbase.enabled` 未设置为 `false`,HBase tokens 将被获得。类似地,如果 Hive 在 classpath 中,其配置包括元数据存储的 URI(`hive.metastore.uris`),并且 `spark.yarn.security.tokens.hive.enabled` 未设置为 `false`,则将获得 Hive token(令牌)。如果应用程序需要与其他安全 Hadoop 文件系统交互,则在启动时必须显式请求访问这些集群所需的 tokens。这是通过将它们列在 1spark.yarn.access.namenodes1 属性中来实现的。``` spark.yarn.access.hadoopFileSystems hdfs://ireland.example.org:8020/,webhdfs://frankfurt.example.org:50070/ ``` Spark 支持通过 Java Services 机制(请看 `java.util.ServiceLoader`)与其它的具有安全性的服务来进行集成。为了实现该目标,通过在 jar 的 `META-INF/services` 目录中列出相应 `org.apache.spark.deploy.yarn.security.ServiceCredentialProvider` 的实现的名字就可应用到 Spark。这些插件可以通过设置 `spark.yarn.security.tokens.{service}.enabled` 为 `false` 来禁用,这里的 `{service}` 是 credential provider(凭证提供者)的名字。## 配置外部的 Shuffle Service 要在 YARN cluster 中的每个 `NodeManager` 中启动 Spark Shuffle,按照以下说明: 1\. 用 [YARN profile](building-spark.html) 来构建 Spark。如果你使用了预包装的发布可以跳过该步骤。1\. 定位 `spark--yarn-shuffle.jar`。如果是你自己构建的 Spark,它应该在 `$SPARK_HOME/common/network-yarn/target/scala-` 下,如果你使用的是一个发布的版本,那么它应该在 `yarn` 下。1\. 添加这个 jar 到你集群中所有的 `NodeManager` 的 classpath 下去。1\. 在每个 node(节点)的 `yarn-site.xml` 文件中,添加 `spark_shuffle` 到 `yarn.nodemanager.aux-services`,然后设置 `yarn.nodemanager.aux-services.spark_shuffle.class` 为 `org.apache.spark.network.yarn.YarnShuffleService`。1\. 通过在 `etc/hadoop/yarn-env.sh` 文件中设置 `YARN_HEAPSIZE` (默认值 1000) 增加 `NodeManager's` 堆大小以避免在 shuffle 时的 garbage collection issues(垃圾回收问题)。1\. 重启集群中所有的 `NodeManager`。当 shuffle service 服务在 YARN 上运行时,可以使用以下额外的配置选项: + # 重要提示 - core request 在调度决策中是否得到执行取决于使用的调度程序及其配置方式。- 在 `cluster 集群` 模式中,Spark executors 和 Spark dirver 使用的本地目录是为 YARN(Hadoop YARN 配置 `yarn.nodemanager.local-dirs`)配置的本地目录。如果用户指定 `spark.local.dir`,它将被忽略。在 `client 客户端` 模式下,Spark executors 将使用为 YARN 配置的本地目录,Spark dirver 将使用 `spark.local.dir` 中定义的目录。这是因为 Spark drivers 不在 YARN cluster 的 `client ` 模式中运行,仅仅 Spark 的 executors 会这样做。- `--files` 和 `--archives` 支持用 # 指定文件名,与 Hadoop 相似。例如您可以指定:`--files localtest.txt#appSees.txt` 然后就会上传本地名为 `localtest.txt` 的文件到 HDFS 中去,但是会通过名称 `appSees.txt` 来链接,当你的应用程序在 YARN 上运行时,你应该使用名称 `appSees.txt` 来引用它。- The `--jars` 选项允许你在 `cluster 集群` 模式下使用本地文件时运行 `SparkContext.addJar` 函数。如果你使用 HDFS,HTTP,HTTPS 或 FTP 文件,则不需要使用它。# 在安全集群中运行 如 [security](security.html) 所讲的,Kerberos 被应用在安全的 Hadoop 集群中去验证与服务和客户端相关联的 principals。这允许客户端请求这些已验证的服务; 向授权的 principals 授予请求服务的权利。Hadoop 服务发出 *hadoop tokens* 去授权访问服务和数据。客户端必须首先获取它们将要访问的服务的 tokens,当启动应用程序时,将它和应用程序一起发送到 YAYN 集群中。如果 Spark 应用程序与其它任何的 Hadoop 文件系统(例如 hdfs,webhdfs,等等),HDFS,HBase 和 Hive 进行交互,它必须使用启动应用程序的用户的 Kerberos 凭据获取相关 tokens,也就是说身份将成为已启动的 Spark 应用程序的 principal。这通常在启动时完成:在安全集群中,Spark 将自动为集群的 HDFS 文件系统获取 tokens,也可能为 HBase 和 Hive 获取。如果 HBase 在 classpath 中,HBase token 是可以获取的,HBase 配置声明应用程序是安全的(即 `hbase-site.xml` 将 `hbase.security.authentication` 设置为 `kerberos`),并且 `spark.yarn.security.tokens.hbase.enabled` 未设置为 `false`,HBase tokens 将被获得。类似地,如果 Hive 在 classpath 中,其配置包括元数据存储的 URI(`hive.metastore.uris`),并且 `spark.yarn.security.tokens.hive.enabled` 未设置为 `false`,则将获得 Hive token(令牌)。如果应用程序需要与其他安全 Hadoop 文件系统交互,则在启动时必须显式请求访问这些集群所需的 tokens。这是通过将它们列在 1spark.yarn.access.namenodes1 属性中来实现的。``` spark.yarn.access.hadoopFileSystems hdfs://ireland.example.org:8020/,webhdfs://frankfurt.example.org:50070/ ``` Spark 支持通过 Java Services 机制(请看 `java.util.ServiceLoader`)与其它的具有安全性的服务来进行集成。为了实现该目标,通过在 jar 的 `META-INF/services` 目录中列出相应 `org.apache.spark.deploy.yarn.security.ServiceCredentialProvider` 的实现的名字就可应用到 Spark。这些插件可以通过设置 `spark.yarn.security.tokens.{service}.enabled` 为 `false` 来禁用,这里的 `{service}` 是 credential provider(凭证提供者)的名字。## 配置外部的 Shuffle Service 要在 YARN cluster 中的每个 `NodeManager` 中启动 Spark Shuffle,按照以下说明:1\. 用 [YARN profile](building-spark.html) 来构建 Spark。如果你使用了预包装的发布可以跳过该步骤。1\. 定位 `spark--yarn-shuffle.jar`。如果是你自己构建的 Spark,它应该在 `$SPARK_HOME/common/network-yarn/target/scala-` 下,如果你使用的是一个发布的版本,那么它应该在 `yarn` 下。1\. 添加这个 jar 到你集群中所有的 `NodeManager` 的 classpath 下去。1\. 在每个 node(节点)的 `yarn-site.xml` 文件中,添加 `spark_shuffle` 到 `yarn.nodemanager.aux-services`,然后设置 `yarn.nodemanager.aux-services.spark_shuffle.class` 为 `org.apache.spark.network.yarn.YarnShuffleService`。1\. 通过在 `etc/hadoop/yarn-env.sh` 文件中设置 `YARN_HEAPSIZE` (默认值 1000) 增加 `NodeManager's` 堆大小以避免在 shuffle 时的 garbage collection issues(垃圾回收问题)。1\. 重启集群中所有的 `NodeManager`。当 shuffle service 服务在 YARN 上运行时,可以使用以下额外的配置选项: | Property Name(属性名称) | Default(默认值) | Meaning(含义) | | --- | --- | --- | @@ -141,4 +141,4 @@ To use a custom metrics.properties for the application master and executors, upd | --- | --- | --- | | `spark.yarn.shuffle.stopOnFailure` | `false` | 是否在 Spark Shuffle Service 初始化出现故障时停止 NodeManager。This prevents application failures caused by running containers on NodeManagers where the Spark Shuffle Service is not running. | -## 用 Apache Oozie 来运行应用程序 Apache Oozie 可以将启动 Spark 应用程序作为工作流的一部分。在安全集群中,启动的应用程序将需要相关的 tokens 来访问集群的服务。如果 Spark 使用 keytab 启动,这是自动的。但是,如果 Spark 在没有 keytab 的情况下启动,则设置安全性的责任必须移交给 Oozie。有关配置 Oozie 以获取安全集群和获取作业凭据的详细信息,请参阅 [Oozie web site](http://oozie.apache.org/) 上特定版本文档的 “Authentication” 部分。对于 Spark 应用程序,必须设置 Oozie 工作流以使 Oozie 请求应用程序需要的所有 tokens,包括: - The YARN resource manager. - The local Hadoop filesystem. - Any remote Hadoop filesystems used as a source or destination of I/O. - Hive —if used. - HBase —if used. - The YARN timeline server, if the application interacts with this. 为了避免 Spark 尝试 - 然后失败 - 要获取 Hive,HBase 和远程的 HDFS 令牌,必须将 Spark 配置收集这些服务 tokens 的选项设置为禁用。Spark 配置必须包含以下行: ``` spark.yarn.security.credentials.hive.enabled false spark.yarn.security.credentials.hbase.enabled false ``` 必须取消设置配置选项`spark.yarn.access.hadoopFileSystems`. ## Kerberos 故障排查 调试 Hadoop/Kerberos 问题可能是 “difficult 困难的”。一个有用的技术是通过设置 `HADOOP_JAAS_DEBUG` 环境变量在 Hadoop 中启用对 Kerberos 操作的额外记录。```bash export HADOOP_JAAS_DEBUG=true ``` JDK 类可以配置为通过系统属性 `sun.security.krb5.debug` 和 `sun.security.spnego.debug=true` 启用对 Kerberos 和 SPNEGO/REST 认证的额外日志记录。``` -Dsun.security.krb5.debug=true -Dsun.security.spnego.debug=true ``` 所有这些选项都可以在 Application Master 中启用: ``` spark.yarn.appMasterEnv.HADOOP_JAAS_DEBUG true spark.yarn.am.extraJavaOptions -Dsun.security.krb5.debug=true -Dsun.security.spnego.debug=true ``` 最后,如果 `org.apache.spark.deploy.yarn.Client` 的日志级别设置为 `DEBUG`,日志将包括获取的所有 tokens 的列表,以及它们的到期详细信息。## 使用 Spark History Server 来替换 Spark Web UI 当应用程序 UI 被禁用时的应用程序,可以使用 Spark History Server 应用程序页面作为运行程序用于跟踪的 URL。这在 secure clusters(安全的集群)中是适合的,或者减少 Spark driver 的内存使用量。要通过 Spark History Server 设置跟踪,请执行以下操作: - 在 application(应用)方面,在 Spark 的配置中设置 `spark.yarn.historyServer.allowTracking=true`. 在 application's UI 是禁用的情况下,这将告诉 Spark 去使用 history server's URL 作为 racking URL。- 在 Spark History Server 方面,添加 `org.apache.spark.deploy.yarn.YarnProxyRedirectFilter` 到 `spark.ui.filters` 配置的中的 filters 列表中去。请注意,history server 信息可能不是应用程序状态的最新信息。 \ No newline at end of file +## 用 Apache Oozie 来运行应用程序 Apache Oozie 可以将启动 Spark 应用程序作为工作流的一部分。在安全集群中,启动的应用程序将需要相关的 tokens 来访问集群的服务。如果 Spark 使用 keytab 启动,这是自动的。但是,如果 Spark 在没有 keytab 的情况下启动,则设置安全性的责任必须移交给 Oozie。有关配置 Oozie 以获取安全集群和获取作业凭据的详细信息,请参阅 [Oozie web site](http://oozie.apache.org/) 上特定版本文档的 “Authentication” 部分。对于 Spark 应用程序,必须设置 Oozie 工作流以使 Oozie 请求应用程序需要的所有 tokens,包括:- The YARN resource manager. - The local Hadoop filesystem. - Any remote Hadoop filesystems used as a source or destination of I/O. - Hive —if used. - HBase —if used. - The YARN timeline server, if the application interacts with this. 为了避免 Spark 尝试 - 然后失败 - 要获取 Hive,HBase 和远程的 HDFS 令牌,必须将 Spark 配置收集这些服务 tokens 的选项设置为禁用。Spark 配置必须包含以下行:``` spark.yarn.security.credentials.hive.enabled false spark.yarn.security.credentials.hbase.enabled false ``` 必须取消设置配置选项`spark.yarn.access.hadoopFileSystems`. ## Kerberos 故障排查 调试 Hadoop/Kerberos 问题可能是 “difficult 困难的”。一个有用的技术是通过设置 `HADOOP_JAAS_DEBUG` 环境变量在 Hadoop 中启用对 Kerberos 操作的额外记录。```bash export HADOOP_JAAS_DEBUG=true ``` JDK 类可以配置为通过系统属性 `sun.security.krb5.debug` 和 `sun.security.spnego.debug=true` 启用对 Kerberos 和 SPNEGO/REST 认证的额外日志记录。``` -Dsun.security.krb5.debug=true -Dsun.security.spnego.debug=true ``` 所有这些选项都可以在 Application Master 中启用:``` spark.yarn.appMasterEnv.HADOOP_JAAS_DEBUG true spark.yarn.am.extraJavaOptions -Dsun.security.krb5.debug=true -Dsun.security.spnego.debug=true ``` 最后,如果 `org.apache.spark.deploy.yarn.Client` 的日志级别设置为 `DEBUG`,日志将包括获取的所有 tokens 的列表,以及它们的到期详细信息。## 使用 Spark History Server 来替换 Spark Web UI 当应用程序 UI 被禁用时的应用程序,可以使用 Spark History Server 应用程序页面作为运行程序用于跟踪的 URL。这在 secure clusters(安全的集群)中是适合的,或者减少 Spark driver 的内存使用量。要通过 Spark History Server 设置跟踪,请执行以下操作:- 在 application(应用)方面,在 Spark 的配置中设置 `spark.yarn.historyServer.allowTracking=true`. 在 application's UI 是禁用的情况下,这将告诉 Spark 去使用 history server's URL 作为 racking URL。- 在 Spark History Server 方面,添加 `org.apache.spark.deploy.yarn.YarnProxyRedirectFilter` 到 `spark.ui.filters` 配置的中的 filters 列表中去。请注意,history server 信息可能不是应用程序状态的最新信息。 \ No newline at end of file diff --git a/docs/18.md b/docs/18.md index 23c75a9..5885565 100644 --- a/docs/18.md +++ b/docs/18.md @@ -1,4 +1,4 @@ # 其它 -* [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 +* [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 diff --git a/docs/20.md b/docs/20.md index e9e5804..36e283c 100644 --- a/docs/20.md +++ b/docs/20.md @@ -98,7 +98,7 @@ val sc = new SparkContext(new SparkConf()) -Spark shell 和 [`spark-submit`](submitting-applications.html) 工具支持两种动态加载配置的方法。第一种,通过命令行选项,如 : 上面提到的 `--master`。`spark-submit` 可以使用 `--conf` flag 来接受任何 Spark 属性标志,但对于启动 Spark 应用程序的属性使用 special flags (特殊标志)。运行 `./bin/spark-submit --help` 可以展示这些选项的完整列表. +Spark shell 和 [`spark-submit`](submitting-applications.html) 工具支持两种动态加载配置的方法。第一种,通过命令行选项,如:上面提到的 `--master`。`spark-submit` 可以使用 `--conf` flag 来接受任何 Spark 属性标志,但对于启动 Spark 应用程序的属性使用 special flags (特殊标志)。运行 `./bin/spark-submit --help` 可以展示这些选项的完整列表. `bin/spark-submit` 也支持从 `conf/spark-defaults.conf` 中读取配置选项,其中每行由一个 key (键)和一个由 whitespace (空格)分隔的 value (值)组成,如下: @@ -126,10 +126,10 @@ spark.serializer org.apache.spark.serializer.KryoSerializer | `spark.app.name` | (none) | Spark 应用的名字。会在 SparkUI 和日志中出现。 | | `spark.driver.cores` | 1 | 在 cluster 模式下,用几个 core 运行 driver 进程。 | | `spark.driver.maxResultSize` | 1g | Spark action 算子返回的结果集的最大数量。至少要 1M,可以设为 0 表示无限制。如果结果超过这一大小,Spark job 会直接中断退出。但是,设得过高有可能导致 driver 出现 out-of-memory 异常(取决于 spark.driver.memory 设置,以及驱动器 JVM 的内存限制)。设一个合理的值,以避免 driver 出现 out-of-memory 异常。 | -| `spark.driver.memory` | 1g | driver进程可以使用的内存总量(如 : `1g`,`2g`)。注意,在 client 模式下,这个配置不能在 SparkConf 中直接设置,应为在那个时候 driver 进程的 JVM 已经启动了。因此需要在命令行里用 --driver-memory 选项 或者在默认属性配置文件里设置。 | +| `spark.driver.memory` | 1g | driver进程可以使用的内存总量(如:`1g`,`2g`)。注意,在 client 模式下,这个配置不能在 SparkConf 中直接设置,应为在那个时候 driver 进程的 JVM 已经启动了。因此需要在命令行里用 --driver-memory 选项 或者在默认属性配置文件里设置。 | | `spark.executor.memory` | 1g | 每个 executor 进程使用的内存总量(如,`2g`,`8g`)。Amount of memory to use per executor process (e.g. `2g`,`8g`). | | `spark.extraListeners` | (none) | 逗号分隔的实现 `SparkListener` 接口的类名列表;初始化 SparkContext 时,这些类的实例会被创建出来,并且注册到 Spark 的监听器上。如果这些类有一个接受 SparkConf 作为唯一参数的构造函数,那么这个构造函数会被调用;否则,就调用无参构造函数。如果没有合适的构造函数,SparkContext 创建的时候会抛异常。 | -| `spark.local.dir` | /tmp | Spark 的”草稿“目录,包括 map 输出的临时文件以及 RDD 存在磁盘上的数据。这个目录最好在本地文件系统中。这个配置可以接受一个以逗号分隔的多个挂载到不同磁盘上的目录列表。注意 : Spark-1.0 及以后版本中,这个属性会被 cluster manager 设置的环境变量覆盖 : SPARK_LOCAL_DIRS(Standalone,Mesos)或者 LOCAL_DIRS(YARN)。 | +| `spark.local.dir` | /tmp | Spark 的”草稿“目录,包括 map 输出的临时文件以及 RDD 存在磁盘上的数据。这个目录最好在本地文件系统中。这个配置可以接受一个以逗号分隔的多个挂载到不同磁盘上的目录列表。注意:Spark-1.0 及以后版本中,这个属性会被 cluster manager 设置的环境变量覆盖:SPARK_LOCAL_DIRS(Standalone,Mesos)或者 LOCAL_DIRS(YARN)。 | | `spark.logConf` | false | SparkContext 启动时是否把生效的 SparkConf 属性以 INFO 日志打印到日志里。 | | `spark.master` | (none) | 要连接的 cluster manager。参考 [Cluster Manager](submitting-applications.html#master-urls) 类型。 | | `spark.submit.deployMode` | (none) | Spark driver 程序的部署模式,可以是 "client" 或 "cluster",意味着部署 dirver 程序本地("client")或者远程("cluster")在 Spark 集群的其中一个节点上。 | @@ -142,7 +142,7 @@ Apart from these, the following properties are also available, and may be useful | Property Name (属性名称) | Default (默认值) | Meaning (含义) | | --- | --- | --- | -| `spark.driver.extraClassPath` | (none) | 额外的classpath条目需预先添加到驱动程序 classpath中。注意 : 在客户端模式下,这一套配置不能通过 SparkConf 直接在应用在应用程序中,因为 JVM 驱动已经启用了。相反,请在配置文件中通过设置 --driver-class-path 选项或者选择默认属性。 | +| `spark.driver.extraClassPath` | (none) | 额外的classpath条目需预先添加到驱动程序 classpath中。注意:在客户端模式下,这一套配置不能通过 SparkConf 直接在应用在应用程序中,因为 JVM 驱动已经启用了。相反,请在配置文件中通过设置 --driver-class-path 选项或者选择默认属性。 | | `spark.driver.extraJavaOptions` | (none) | 一些额外的 JVM 属性传递给驱动。例如,GC 设置或其他日志方面设置。注意,设置最大堆大小(-Xmx)是不合法的。最大堆大小设置可以通过在集群模式下设置 `spark.driver.memory` 选项,并且可以通过`--driver-memory` 在客户端模式设置。 _注意:_ 在客户端模式下,这一套配置不能通过 `SparkConf` 直接应用在应用程序中,因为 JVM 驱动已经启用了。相反,请在配置文件中通过设置 `--driver-java-options` 选项或者选择默认属性。 | | `spark.driver.extraLibraryPath` | (none) | 当启动 JVM 驱动程序时设置一个额外的库路径。 @@ -222,13 +222,13 @@ _注意:_ 在客户端模式下,这一套配置不能通过 `SparkConf` 直接 | Property Name (属性名称) | Default (默认值) | Meaning (含义) | | --- | --- | --- | | `spark.broadcast.compress` | true | 是否在发送之前压缩广播变量。一般是个好主意压缩将使用 `spark.io.compression.codec`。 | -| `spark.io.compression.codec` | lz4 | 内部数据使用的压缩编解码器,如 RDD 分区,广播变量和混洗输出。默认情况下,Spark 提供三种编解码器 : `lz4`,`lzf`,和 `snappy`。您还可以使用完全限定类名来指定编码解码器, 例如 : `org.apache.spark.io.LZ4CompressionCodec`, `org.apache.spark.io.LZFCompressionCodec`, 和 `org.apache.spark.io.SnappyCompressionCodec`。 | +| `spark.io.compression.codec` | lz4 | 内部数据使用的压缩编解码器,如 RDD 分区,广播变量和混洗输出。默认情况下,Spark 提供三种编解码器:`lz4`,`lzf`,和 `snappy`。您还可以使用完全限定类名来指定编码解码器, 例如:`org.apache.spark.io.LZ4CompressionCodec`, `org.apache.spark.io.LZFCompressionCodec`, 和 `org.apache.spark.io.SnappyCompressionCodec`。 | | `spark.io.compression.lz4.blockSize` | 32k | 在采用 LZ4 压缩编解码器的情况下,LZ4 压缩使用的块大小。减少块大小还将降低采用 LZ4 时的混洗内存使用。 | | `spark.io.compression.snappy.blockSize` | 32k | 在采用 Snappy 压缩编解码器的情况下,Snappy 压缩使用的块大小。减少块大小还将降低采用 Snappy 时的混洗内存使用。 | | `spark.kryo.classesToRegister` | (none) | 如果你采用 Kryo 序列化,给一个以逗号分隔的自定义类名列以注册 Kryo。有关详细信息,请参阅[调优指南](tuning.html#data-serialization)。 | | `spark.kryo.referenceTracking` | true | 当使用 Kryo 序列化数据时,是否跟踪对同一对象的引用,如果对象图具有循环,并且如果它们包含同一对象的多个副本对效率有用,则这是必需的。如果您知道这不是这样,可以禁用此功能来提高性能。 | | `spark.kryo.registrationRequired` | false | 是否需要注册 Kryo。如果设置为 'true',如果未注册的类被序列化,Kryo 将抛出异常。如果设置为 false(默认值),Kryo 将与每个对象一起写入未注册的类名。编写类名可能会导致显著的性能开销,因此启用此选项可以严格强制用户没有从注册中省略类。 | -| `spark.kryo.registrator` | (none) | 如果你采用 Kryo 序列化,则给一个逗号分隔的类列表,以使用 Kryo 注册你的自定义类。如果你需要以自定义方式注册你的类,则此属性很有用,例如以指定自定义字段序列化程序。否则,使用 spark.kryo.classesToRegisteris 更简单。它应该设置为 [`KryoRegistrator`](api/scala/index.html#org.apache.spark.serializer.KryoRegistrator) 的子类。详见 : [调整指南](tuning.html#data-serialization)。 | +| `spark.kryo.registrator` | (none) | 如果你采用 Kryo 序列化,则给一个逗号分隔的类列表,以使用 Kryo 注册你的自定义类。如果你需要以自定义方式注册你的类,则此属性很有用,例如以指定自定义字段序列化程序。否则,使用 spark.kryo.classesToRegisteris 更简单。它应该设置为 [`KryoRegistrator`](api/scala/index.html#org.apache.spark.serializer.KryoRegistrator) 的子类。详见:[调整指南](tuning.html#data-serialization)。 | | `spark.kryo.unsafe` | false | Whether to use unsafe based Kryo serializer. Can be substantially faster by using Unsafe Based IO. | | `spark.kryoserializer.buffer.max` | 64m | Kryo 序列化缓冲区的最大允许大小。这必须大于你需要序列化的任何对象。如果你在 Kryo 中得到一个 “buffer limit exceeded” 异常,你就需要增加这个值。 | | `spark.kryoserializer.buffer` | 64k | Kryo 序列化缓冲区的初始大小。注意,每个 worker上 _每个 core_ 会有一个缓冲区。如果需要,此缓冲区将增长到 `spark.kryoserializer.buffer.max`。 | @@ -245,7 +245,7 @@ JavaSerializer | 用于序列化将通过网络发送或需要以序列化形式 | `spark.memory.storageFraction` | 0.5 | 不会被逐出内存的总量,表示为 `s​park.memory.fraction` 留出的区域大小的一小部分。这个越高,工作内存可能越少,执行和任务可能更频繁地溢出到磁盘。推荐使用默认值。有关更多详细信息,请参阅 [this description](tuning.html#memory-management-overview)。 | | `spark.memory.offHeap.enabled` | false | 如果为 true,Spark 会尝试对某些操作使用堆外内存。如果启用了堆外内存使用,则 `spark.memory.offHeap.size` 必须为正值。 | | `spark.memory.offHeap.size` | 0 | 可用于堆外分配的绝对内存量(以字节为单位)。此设置对堆内存使用没有影响,因此如果您的执行器的总内存消耗必须满足一些硬限制,那么请确保相应地缩减JVM堆大小。当 `spark.memory.offHeap.enabled=true` 时,必须将此值设置为正值。 | -| `spark.memory.useLegacyMode` | false | 是否启用 Spark 1.5 及以前版本中使用的传统内存管理模式。传统模式将堆空间严格划分为固定大小的区域,如果未调整应用程序,可能导致过多溢出。必须启用本参数,以下选项才可用 : `spark.shuffle.memoryFraction` +| `spark.memory.useLegacyMode` | false | 是否启用 Spark 1.5 及以前版本中使用的传统内存管理模式。传统模式将堆空间严格划分为固定大小的区域,如果未调整应用程序,可能导致过多溢出。必须启用本参数,以下选项才可用:`spark.shuffle.memoryFraction` `spark.storage.memoryFraction` `spark.storage.unrollFraction` | | `spark.shuffle.memoryFraction` | 0.2 | (过时)只有在启用 `spark.memory.useLegacyMode` 时,此属性才是可用的。混洗期间用于聚合和 cogroups 的 Java 堆的分数。在任何给定时间,用于混洗的所有内存映射的集合大小不会超过这个上限,超过该限制的内容将开始溢出到磁盘。如果溢出频繁,请考虑增加此值,但这以 `spark.storage.memoryFraction` 为代价。 | @@ -261,9 +261,9 @@ JavaSerializer | 用于序列化将通过网络发送或需要以序列化形式 | `spark.executor.cores` | 在 YARN 模式下默认为 1,standlone 和 Mesos 粗粒度模型中的 worker 节点的所有可用的 core。 | 在每个 executor(执行器)上使用的 core 数。在 standlone 和 Mesos 的粗粒度模式下,设置此参数允许应用在相同的 worker 上运行多个 executor(执行器),只要该 worker 上有足够的 core。否则,每个 application(应用)在单个 worker 上只会启动一个 executor(执行器)。 | | `spark.default.parallelism` | 对于分布式混洗(shuffle)操作,如 `reduceByKey` 和 `join`,父 RDD 中分区的最大数量。对于没有父 RDD 的 `parallelize` 操作,它取决于集群管理器 : -* 本地模式 : 本地机器上的 core 数 -* Mesos 细粒度模式 : 8 -* 其他 : 所有执行器节点上的 core 总数或者 2,以较大者为准 +* 本地模式:本地机器上的 core 数 +* Mesos 细粒度模式:8 +* 其他:所有执行器节点上的 core 总数或者 2,以较大者为准 | 如果用户没有指定参数值,则这个属性是 `join`,`reduceByKey`,和 `parallelize` 等转换返回的 RDD 中的默认分区数。 | | `spark.executor.heartbeatInterval` | 10s | 每个执行器的心跳与驱动程序之间的间隔。心跳让驱动程序知道执行器仍然存活,并用正在进行的任务的指标更新它 | @@ -335,7 +335,7 @@ It also allows a different address from the local one to be advertised to execut | --- | --- | --- | | `spark.dynamicAllocation.enabled` | false | 是否使用动态资源分配,它根据工作负载调整为此应用程序注册的执行程序数量。有关更多详细信息,请参阅 [here](job-scheduling.html#dynamic-resource-allocation) 的说明. -这需要设置 `spark.shuffle.service.enabled`。以下配置也相关 : `spark.dynamicAllocation.minExecutors`,`spark.dynamicAllocation.maxExecutors` 和`spark.dynamicAllocation.initialExecutors`。 | +这需要设置 `spark.shuffle.service.enabled`。以下配置也相关:`spark.dynamicAllocation.minExecutors`,`spark.dynamicAllocation.maxExecutors` 和`spark.dynamicAllocation.initialExecutors`。 | | `spark.dynamicAllocation.executorIdleTimeout` | 60s | 如果启用动态分配,并且执行程序已空闲超过此持续时间,则将删除执行程序。有关更多详细信息,请参阅此[description](job-scheduling.html#resource-allocation-policy)。 | | `spark.dynamicAllocation.cachedExecutorIdleTimeout` | infinity | 如果启用动态分配,并且已缓存数据块的执行程序已空闲超过此持续时间,则将删除执行程序。有关详细信息,请参阅此 [description](job-scheduling.html#resource-allocation-policy)。 | | `spark.dynamicAllocation.initialExecutors` | `spark.dynamicAllocation.minExecutors` | 启用动态分配时要运行的执行程序的初始数. @@ -492,7 +492,7 @@ Spark 中的每个集群管理器都有额外的配置选项,这些配置可 # Environment Variables (环境变量) 通过环境变量配置特定的 Spark 设置。环境变量从 Spark 安装目录下的 `conf/spark-env.sh` 脚本读取(或者是 window 环境下的 `conf/spark-env.cmd` )。在 Standalone 和 Mesos 模式下,这个文件可以指定机器的特定信息,比如 hostnames。它也可以为正在运行的 Spark Application 或者提交脚本提供 sourced (来源). -注意,当 Spark 被安装,默认情况下 `conf/spark-env.sh` 是不存在的。但是,你可以通过拷贝 `conf/spark-env.sh.template` 来创建它。确保你的拷贝文件时可执行的。`spark-env.sh` : 中有有以下变量可以被设置 : +注意,当 Spark 被安装,默认情况下 `conf/spark-env.sh` 是不存在的。但是,你可以通过拷贝 `conf/spark-env.sh.template` 来创建它。确保你的拷贝文件时可执行的。`spark-env.sh`:中有有以下变量可以被设置 : | Environment Variable (环境变量) | Meaning (含义) | | --- | --- | @@ -507,7 +507,7 @@ Spark 中的每个集群管理器都有额外的配置选项,这些配置可 因为 `spark-env.sh` 是 shell 脚本,一些可以通过程序的方式来设置,比如你可以通过特定的网络接口来计算 `SPARK_LOCAL_IP` . -注意 : 当以 `cluster` mode (集群模式)运行 Spark on YARN 时,环境变量需要通过在您的 `conf/spark-defaults.conf` 文件中 `spark.yarn.appMasterEnv.[EnvironmentVariableName]` 来设定。`cluster` mode (集群模式)下,`spark-env.sh` 中设定的环境变量将不会在 YARN Application Master 过程中反应出来。详见 [YARN-related Spark Properties](running-on-yarn.html#spark-properties). +注意:当以 `cluster` mode (集群模式)运行 Spark on YARN 时,环境变量需要通过在您的 `conf/spark-defaults.conf` 文件中 `spark.yarn.appMasterEnv.[EnvironmentVariableName]` 来设定。`cluster` mode (集群模式)下,`spark-env.sh` 中设定的环境变量将不会在 YARN Application Master 过程中反应出来。详见 [YARN-related Spark Properties](running-on-yarn.html#spark-properties). # Configuring Logging (配置 Logging) diff --git a/docs/21.md b/docs/21.md index 4166e69..de5192f 100644 --- a/docs/21.md +++ b/docs/21.md @@ -140,7 +140,7 @@ Example: `?offset=10&length=50&sortBy=runtime` | * 任何给定 endpoint都不会删除个别字段 * 可以添加新的 endpoint * 可以将新字段添加到现有 endpoint -* 将来可能会在单独的 endpoint添加新版本的api(例如: `api/v2`)。新版本 _不_ 需要向后兼容。 +* 将来可能会在单独的 endpoint添加新版本的api(例如:`api/v2`)。新版本 _不_ 需要向后兼容。 * Api版本可能会被删除,但只有在至少一个与新的api版本共存的次要版本之后才可以删除。 请注意,即使在检查正在运行的应用程序的UI时,仍然需要 `applications/[app-id]`部分,尽管只有一个应用程序可用。例如:要查看正在运行的应用程序的作业列表,您可以访问 `http://localhost:4040/api/v1/applications/[app-id]/jobs`。这是为了在两种模式下保持路径一致。 @@ -151,25 +151,25 @@ Spark具有基于[Dropwizard Metrics Library](http://metrics.dropwizard.io/)的 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. +* `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。 +* `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`:向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`工件。 diff --git a/docs/22.md b/docs/22.md index 1b9b03d..48ceac8 100644 --- a/docs/22.md +++ b/docs/22.md @@ -20,8 +20,8 @@ 序列化在任何分布式应用程序的性能中起着重要的作用。很慢的将对象序列化或消费大量字节的格式将会大大减慢计算速度。通常,这可能是您优化 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` 类型,并且需要先_注册_您将在程序中使用的类以获得最佳性能。 +* [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。 diff --git a/docs/23.md b/docs/23.md index 98c5b6d..d3b8435 100644 --- a/docs/23.md +++ b/docs/23.md @@ -75,9 +75,9 @@ Spark会分轮次来申请执行器。实际的资源申请,会在任务挂起 # 应用内调度 -在指定的 Spark 应用内部(对应同一 SparkContext 实例),多个线程可能并发地提交 Spark 作业(job)。在本节中,作业(job)是指,由 Spark action 算子(如 : collect)触发的一系列计算任务的集合。Spark 调度器是完全线程安全的,并且能够支持 Spark 应用同时处理多个请求(比如 : 来自不同用户的查询)。 +在指定的 Spark 应用内部(对应同一 SparkContext 实例),多个线程可能并发地提交 Spark 作业(job)。在本节中,作业(job)是指,由 Spark action 算子(如:collect)触发的一系列计算任务的集合。Spark 调度器是完全线程安全的,并且能够支持 Spark 应用同时处理多个请求(比如:来自不同用户的查询)。 -默认,Spark 应用内部使用 FIFO 调度策略。每个作业被划分为多个阶段(stage)(例如 : map 阶段和 reduce 阶段),第一个作业在其启动后会优先获取所有的可用资源,然后是第二个作业再申请,再第三个……。如果前面的作业没有把集群资源占满,则后续的作业可以立即启动运行,否则,后提交的作业会有明显的延迟等待。 +默认,Spark 应用内部使用 FIFO 调度策略。每个作业被划分为多个阶段(stage)(例如:map 阶段和 reduce 阶段),第一个作业在其启动后会优先获取所有的可用资源,然后是第二个作业再申请,再第三个……。如果前面的作业没有把集群资源占满,则后续的作业可以立即启动运行,否则,后提交的作业会有明显的延迟等待。 不过从 Spark 0.8 开始,Spark 也能支持各个作业间的公平(Fair)调度。公平调度时,Spark 以轮询的方式给每个作业分配资源,因此所有的作业获得的资源大体上是平均分配。这意味着,即使有大作业在运行,小的作业再提交也能立即获得计算资源而不是等待前面的作业结束,大大减少了延迟时间。这种模式特别适合于多用户配置。要启用公平调度器,只需设置一下 SparkContext 中 spark.scheduler.mode 属性为 FAIR 即可 : @@ -93,7 +93,7 @@ val sc = new SparkContext(conf) ## 公平调度资源池 -公平调度器还可以支持将作业分组放入资源池(pool),然后给每个资源池配置不同的选项(如 : 权重)。这样你就可以给一些比较重要的作业创建一个“高优先级”资源池,或者你也可以把每个用户的作业分到一组,这样一来就是各个用户平均分享集群资源,而不是各个作业平分集群资源。Spark 公平调度的实现方式基本都是模仿 [Hadoop Fair Scheduler](http://hadoop.apache.org/docs/current/hadoop-yarn/hadoop-yarn-site/FairScheduler.html)。来实现的。 +公平调度器还可以支持将作业分组放入资源池(pool),然后给每个资源池配置不同的选项(如:权重)。这样你就可以给一些比较重要的作业创建一个“高优先级”资源池,或者你也可以把每个用户的作业分到一组,这样一来就是各个用户平均分享集群资源,而不是各个作业平分集群资源。Spark 公平调度的实现方式基本都是模仿 [Hadoop Fair Scheduler](http://hadoop.apache.org/docs/current/hadoop-yarn/hadoop-yarn-site/FairScheduler.html)。来实现的。 默认情况下,新提交的作业都会进入到默认资源池中,不过作业对应于哪个资源池,可以在提交作业的线程中用 SparkContext.setLocalProperty 设定 spark.scheduler.pool 属性。示例代码如下 : @@ -106,7 +106,7 @@ sc.setLocalProperty("spark.scheduler.pool", "pool1") -一旦设好了局部属性,所有该线程所提交的作业(即 : 在该线程中调用action算子,如 : RDD.save/count/collect 等)都会使用这个资源池。这个设置是以线程为单位保存的,你很容易实现用同一线程来提交同一用户的所有作业到同一个资源池中。同样,如果需要清除资源池设置,只需在对应线程中调用如下代码 : +一旦设好了局部属性,所有该线程所提交的作业(即:在该线程中调用action算子,如:RDD.save/count/collect 等)都会使用这个资源池。这个设置是以线程为单位保存的,你很容易实现用同一线程来提交同一用户的所有作业到同一个资源池中。同样,如果需要清除资源池设置,只需在对应线程中调用如下代码 : @@ -124,9 +124,9 @@ sc.setLocalProperty("spark.scheduler.pool", null) 资源池的属性需要通过配置文件来指定。每个资源池都支持以下3个属性 : -* `schedulingMode`: 可以是 FIFO 或 FAIR,控制资源池内部的作业是如何调度的。 -* `weight`: 控制资源池相对其他资源池,可以分配到资源的比例。默认所有资源池的 weight 都是 1。如果你将某个资源池的 weight 设为 2,那么该资源池中的资源将是其他池子的2倍。如果将 weight 设得很高,如 1000,可以实现资源池之间的调度优先级 – 也就是说,weight=1000 的资源池总能立即启动其对应的作业。 -* `minShare`: 除了整体 weight 之外,每个资源池还能指定一个最小资源分配值(CPU 个数),管理员可能会需要这个设置。公平调度器总是会尝试优先满足所有活跃(active)资源池的最小资源分配值,然后再根据各个池子的 weight 来分配剩下的资源。因此,minShare 属性能够确保每个资源池都能至少获得一定量的集群资源。minShare 的默认值是 0。 +* `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 属性指定文件路径: diff --git a/docs/25.md b/docs/25.md index a024c5a..d0f2c9c 100644 --- a/docs/25.md +++ b/docs/25.md @@ -6,7 +6,7 @@ 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。最简单的方法是在相同节点上设置 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。 diff --git a/docs/28.md b/docs/28.md index dad16b2..e3f87a6 100644 --- a/docs/28.md +++ b/docs/28.md @@ -1,4 +1,4 @@ # 其它 * [给 Spark 贡献](http://spark.apache.org/contributing.html) -* [第三方项目](http://spark.apache.org/third-party-projects.html): 其它第三方 Spark 项目的支持 \ No newline at end of file +* [第三方项目](http://spark.apache.org/third-party-projects.html):其它第三方 Spark 项目的支持 \ No newline at end of file diff --git a/docs/29.md b/docs/29.md index d2873cd..c7ae714 100644 --- a/docs/29.md +++ b/docs/29.md @@ -3,6 +3,6 @@ * [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 +* [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 diff --git a/docs/30.md b/docs/30.md index 654f7a2..b21e5f8 100644 --- a/docs/30.md +++ b/docs/30.md @@ -3,23 +3,23 @@ ## 前言 感谢大家默默的无私付出,感谢 [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#联系方式) +网址:[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/) +* 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 | 工期 | 开始时间 | 结束时间 | 贡献者 | 备注 | | --- | --- | --- | --- | --- | --- | --- | --- | --- | diff --git a/docs/4.md b/docs/4.md index a05ba82..5cd0298 100644 --- a/docs/4.md +++ b/docs/4.md @@ -35,7 +35,7 @@ 在一个较高的概念上来说,每一个 Spark 应用程序由一个在集群上运行着用户的 `main` 函数和执行各种并行操作的 _driver program_(驱动程序)组成。Spark 提供的主要抽象是一个_弹性分布式数据集_(RDD),它是可以执行并行操作且跨集群节点的元素的集合。RDD 可以从一个 Hadoop 文件系统(或者任何其它 Hadoop 支持的文件系统),或者一个在 driver program(驱动程序)中已存在的 Scala 集合,以及通过 transforming(转换)来创建一个 RDD。用户为了让它在整个并行操作中更高效的重用,也许会让 Spark persist(持久化)一个 RDD 到内存中。最后,RDD 会自动的从节点故障中恢复。 -在 Spark 中的第二个抽象是能够用于并行操作的 _shared variables_(共享变量),默认情况下,当 Spark 的一个函数作为一组不同节点上的任务运行时,它将每一个变量的副本应用到每一个任务的函数中去。有时候,一个变量需要在整个任务中,或者在任务和 driver program(驱动程序)之间来共享。Spark 支持两种类型的共享变量 : _broadcast variables_(广播变量),它可以用于在所有节点上缓存一个值,和 _accumulators_(累加器),他是一个只能被 “added(增加)” 的变量,例如 counters 和 sums。 +在 Spark 中的第二个抽象是能够用于并行操作的 _shared variables_(共享变量),默认情况下,当 Spark 的一个函数作为一组不同节点上的任务运行时,它将每一个变量的副本应用到每一个任务的函数中去。有时候,一个变量需要在整个任务中,或者在任务和 driver program(驱动程序)之间来共享。Spark 支持两种类型的共享变量:_broadcast variables_(广播变量),它可以用于在所有节点上缓存一个值,和 _accumulators_(累加器),他是一个只能被 “added(增加)” 的变量,例如 counters 和 sums。 本指南介绍了每一种 Spark 所支持的语言的特性。如果您启动 Spark 的交互式 shell - 针对 Scala shell 使用 `bin/spark-shell` 或者针对 Python 使用 `bin/pyspark` 是很容易来学习的。 @@ -254,7 +254,7 @@ After the Jupyter Notebook server is launched, you can create a new “Python 2 # 弹性分布式数据集 (RDDs) -Spark 主要以一个 _弹性分布式数据集_(RDD)的概念为中心,它是一个容错且可以执行并行操作的元素的集合。有两种方法可以创建 RDD : 在你的 driver program(驱动程序)中 _parallelizing_ 一个已存在的集合,或者在外部存储系统中引用一个数据集,例如,一个共享文件系统,HDFS,HBase,或者提供 Hadoop InputFormat 的任何数据源。 +Spark 主要以一个 _弹性分布式数据集_(RDD)的概念为中心,它是一个容错且可以执行并行操作的元素的集合。有两种方法可以创建 RDD:在你的 driver program(驱动程序)中 _parallelizing_ 一个已存在的集合,或者在外部存储系统中引用一个数据集,例如,一个共享文件系统,HDFS,HBase,或者提供 Hadoop InputFormat 的任何数据源。 ## 并行集合 @@ -297,7 +297,7 @@ distData = sc.parallelize(data) Once created, the distributed dataset (`distData`) can be operated on in parallel. For example, we can call `distData.reduce(lambda a, b: a + b)` to add up the elements of the list. We describe operations on distributed datasets later on. -并行集合中一个很重要参数是 _partitions_(分区)的数量,它可用来切割 dataset(数据集)。Spark 将在集群中的每一个分区上运行一个任务。通常您希望群集中的每一个 CPU 计算 2-4 个分区。一般情况下,Spark 会尝试根据您的群集情况来自动的设置的分区的数量。当然,您也可以将分区数作为第二个参数传递到 `parallelize` (e.g. `sc.parallelize(data, 10)`) 方法中来手动的设置它。注意: 代码中的一些地方会使用 term slices (a synonym for partitions) 以保持向后兼容. +并行集合中一个很重要参数是 _partitions_(分区)的数量,它可用来切割 dataset(数据集)。Spark 将在集群中的每一个分区上运行一个任务。通常您希望群集中的每一个 CPU 计算 2-4 个分区。一般情况下,Spark 会尝试根据您的群集情况来自动的设置的分区的数量。当然,您也可以将分区数作为第二个参数传递到 `parallelize` (e.g. `sc.parallelize(data, 10)`) 方法中来手动的设置它。注意:代码中的一些地方会使用 term slices (a synonym for partitions) 以保持向后兼容. ## 外部 Datasets(数据集) @@ -314,7 +314,7 @@ distFile: org.apache.spark.rdd.RDD[String] = data.txt MapPartitionsRDD[10] at te -在创建后,`distFile` 可以使用 dataset(数据集)的操作。例如,我们可以使用下面的 map 和 reduce 操作来合计所有行的数量: `distFile.map(s => s.length).reduce((a, b) => a + b)`。 +在创建后,`distFile` 可以使用 dataset(数据集)的操作。例如,我们可以使用下面的 map 和 reduce 操作来合计所有行的数量:`distFile.map(s => s.length).reduce((a, b) => a + b)`。 使用 Spark 读取文件时需要注意: @@ -460,7 +460,7 @@ See the [Python examples](https://github.com/apache/spark/tree/master/examples/s ## RDD 操作 -RDDs support 两种类型的操作: _transformations(转换)_,它会在一个已存在的 dataset 上创建一个新的 dataset,和 _actions(动作)_,将在 dataset 上运行的计算后返回到 driver 程序。例如,`map` 是一个通过让每个数据集元素都执行一个函数,并返回的新 RDD 结果的 transformation,`reduce` reduce 通过执行一些函数,聚合 RDD 中所有元素,并将最终结果给返回驱动程序(虽然也有一个并行 `reduceByKey` 返回一个分布式数据集)的 action. +RDDs support 两种类型的操作:_transformations(转换)_,它会在一个已存在的 dataset 上创建一个新的 dataset,和 _actions(动作)_,将在 dataset 上运行的计算后返回到 driver 程序。例如,`map` 是一个通过让每个数据集元素都执行一个函数,并返回的新 RDD 结果的 transformation,`reduce` reduce 通过执行一些函数,聚合 RDD 中所有元素,并将最终结果给返回驱动程序(虽然也有一个并行 `reduceByKey` 返回一个分布式数据集)的 action. Spark 中所有的 transformations 都是 _lazy(懒加载的)_,因此它不会立刻计算出结果。相反,他们只记得应用于一些基本数据集的转换 (例如. 文件)。只有当需要返回结果给驱动程序时,transformations 才开始计算。这种设计使 Spark 的运行更高效。例如,我们可以了解到,`map` 所创建的数据集将被用在 `reduce` 中,并且只有 `reduce` 的计算结果返回给驱动程序,而不是映射一个更大的数据集. @@ -480,7 +480,7 @@ val totalLength = lineLengths.reduce((a, b) => a + b) -第一行从外部文件中定义了一个基本的 RDD,但这个数据集并未加载到内存中或即将被行动: `line` 仅仅是一个类似指针的东西,指向该文件。第二行定义了 `lineLengths` 作为 `map` transformation 的结果。请注意,由于 `laziness`(延迟加载)`lineLengths` 不会被立即计算。最后,我们运行 `reduce`,这是一个 action。此时,Spark 分发计算任务到不同的机器上运行,每台机器都运行在 map 的一部分并本地运行 reduce,仅仅返回它聚合后的结果给驱动程序. +第一行从外部文件中定义了一个基本的 RDD,但这个数据集并未加载到内存中或即将被行动:`line` 仅仅是一个类似指针的东西,指向该文件。第二行定义了 `lineLengths` 作为 `map` transformation 的结果。请注意,由于 `laziness`(延迟加载)`lineLengths` 不会被立即计算。最后,我们运行 `reduce`,这是一个 action。此时,Spark 分发计算任务到不同的机器上运行,每台机器都运行在 map 的一部分并本地运行 reduce,仅仅返回它聚合后的结果给驱动程序. 如果我们也希望以后再次使用 `lineLengths`,我们还可以添加: @@ -780,7 +780,7 @@ print("Counter value: ", counter) #### 打印 RDD 的 elements -另一种常见的语法用于打印 RDD 的所有元素使用 `rdd.foreach(println)` 或 `rdd.map(println)`。在一台机器上,这将产生预期的输出和打印 RDD 的所有元素。然而,在集群 `cluster` 模式下,`stdout` 输出正在被执行写操作 executors 的 `stdout` 代替,而不是在一个驱动程序上,因此 `stdout` 的 `driver` 程序不会显示这些!要打印 `driver` 程序的所有元素,可以使用的 `collect()` 方法首先把 RDD 放到 driver 程序节点上: `rdd.collect().foreach(println)`。这可能会导致 driver 程序耗尽内存,虽说,因为 `collect()` 获取整个 RDD 到一台机器; 如果你只需要打印 RDD 的几个元素,一个更安全的方法是使用 `take()`: `rdd.take(100).foreach(println)`。 +另一种常见的语法用于打印 RDD 的所有元素使用 `rdd.foreach(println)` 或 `rdd.map(println)`。在一台机器上,这将产生预期的输出和打印 RDD 的所有元素。然而,在集群 `cluster` 模式下,`stdout` 输出正在被执行写操作 executors 的 `stdout` 代替,而不是在一个驱动程序上,因此 `stdout` 的 `driver` 程序不会显示这些!要打印 `driver` 程序的所有元素,可以使用的 `collect()` 方法首先把 RDD 放到 driver 程序节点上:`rdd.collect().foreach(println)`。这可能会导致 driver 程序耗尽内存,虽说,因为 `collect()` 获取整个 RDD 到一台机器; 如果你只需要打印 RDD 的几个元素,一个更安全的方法是使用 `take()`:`rdd.take(100).foreach(println)`。 ### 与 Key-Value Pairs 一起使用 @@ -970,7 +970,7 @@ Spark 会自动监视每个节点上的缓存使用情况,并使用 least-rece # 共享变量 -通常情况下,一个传递给 Spark 操作(例如 `map` 或 `reduce`)的函数 func 是在远程的集群节点上执行的。该函数 func 在多个节点执行过程中使用的变量,是同一个变量的多个副本。这些变量的以副本的方式拷贝到每个机器上,并且各个远程机器上变量的更新并不会传播回 driver program(驱动程序)。通用且支持 read-write(读-写) 的共享变量在任务间是不能胜任的。所以,Spark 提供了两种特定类型的共享变量 : broadcast variables(广播变量)和 accumulators(累加器)。 +通常情况下,一个传递给 Spark 操作(例如 `map` 或 `reduce`)的函数 func 是在远程的集群节点上执行的。该函数 func 在多个节点执行过程中使用的变量,是同一个变量的多个副本。这些变量的以副本的方式拷贝到每个机器上,并且各个远程机器上变量的更新并不会传播回 driver program(驱动程序)。通用且支持 read-write(读-写) 的共享变量在任务间是不能胜任的。所以,Spark 提供了两种特定类型的共享变量:broadcast variables(广播变量)和 accumulators(累加器)。 ## 广播变量 @@ -1025,7 +1025,7 @@ Accumulators(累加器)是一个仅可以执行 “added”(添加)的 ![Accumulators in the Spark UI](img/15dfb146313300f30241c551010cf1a0.jpg "Accumulators in the Spark UI") -在 UI 中跟踪累加器可以有助于了解运行阶段的进度(注: 这在 Python 中尚不支持). +在 UI 中跟踪累加器可以有助于了解运行阶段的进度(注:这在 Python 中尚不支持). 可以通过调用 `SparkContext.longAccumulator()` 或 `SparkContext.doubleAccumulator()` 方法创建数值类型的 `accumulator`(累加器)以分别累加 Long 或 Double 类型的值。集群上正在运行的任务就可以使用 `add` 方法来累计数值。然而,它们不能够读取它的值。只有 driver program(驱动程序)才可以使用 `value` 方法读取累加器的值。 @@ -1047,7 +1047,7 @@ res2: Long = 10 -虽然此代码使用 Long 类型的累加器的内置支持,但是开发者通过 [AccumulatorV2](api/scala/index.html#org.apache.spark.util.AccumulatorV2) 它的子类来创建自己的类型。AccumulatorV2 抽象类有几个需要 override(重写)的方法: `reset` 方法可将累加器重置为 0,`add` 方法可将其它值添加到累加器中,`merge` 方法可将其他同样类型的累加器合并为一个。其他需要重写的方法可参考 [API documentation](api/scala/index.html#org.apache.spark.util.AccumulatorV2)。例如,假设我们有一个表示数学上 vectors(向量)的 `MyVector` 类,我们可以写成: +虽然此代码使用 Long 类型的累加器的内置支持,但是开发者通过 [AccumulatorV2](api/scala/index.html#org.apache.spark.util.AccumulatorV2) 它的子类来创建自己的类型。AccumulatorV2 抽象类有几个需要 override(重写)的方法:`reset` 方法可将累加器重置为 0,`add` 方法可将其它值添加到累加器中,`merge` 方法可将其他同样类型的累加器合并为一个。其他需要重写的方法可参考 [API documentation](api/scala/index.html#org.apache.spark.util.AccumulatorV2)。例如,假设我们有一个表示数学上 vectors(向量)的 `MyVector` 类,我们可以写成: diff --git a/docs/6.md b/docs/6.md index 2717bec..5fbadaa 100644 --- a/docs/6.md +++ b/docs/6.md @@ -96,7 +96,7 @@ val pairs = words.map(word => (word, 1)) val wordCounts = pairs.reduceByKey(_ + _) // 在控制台打印出在这个离散流(DStream)中生成的每个 RDD 的前十个元素 -// 注意: 必需要触发 action(很多初学者会忘记触发 action 操作,导致报错:No output operations registered, so nothing to execute) +// 注意:必需要触发 action(很多初学者会忘记触发 action 操作,导致报错:No output operations registered, so nothing to execute) wordCounts.print() ``` @@ -528,8 +528,8 @@ The batch interval must be set based on the latency requirements of your applica Spark Streaming 提供了两种内置的 streaming source(流的数据源). -* _Basic sources(基础的数据源)_: 在 StreamingContext API 中直接可以使用的数据源。例如: file systems 和 socket connections. -* _Advanced sources(高级的数据源)_: 像 Kafka,Flume,Kinesis,等等这样的数据源。可以通过额外的 utility classes 来使用。像在 [依赖](#依赖) 中讨论的一样,这些都需要额外的外部依赖. +* _Basic sources(基础的数据源)_:在 StreamingContext API 中直接可以使用的数据源。例如:file systems 和 socket connections. +* _Advanced sources(高级的数据源)_:像 Kafka,Flume,Kinesis,等等这样的数据源。可以通过额外的 utility classes 来使用。像在 [依赖](#依赖) 中讨论的一样,这些都需要额外的外部依赖. 在本节的后边,我们将讨论每种类别中的现有的一些数据源. @@ -934,10 +934,10 @@ DStream 转换的完整列表可在 API 文档中找到。针对 Scala API,请 | --- | --- | | **print**() | 在运行流应用程序的 driver 节点上的DStream中打印每批数据的前十个元素。这对于开发和调试很有用. Python API 这在 Python API 中称为 **pprint()**。 -| **saveAsTextFiles**(_prefix_, [_suffix_]) | 将此 DStream 的内容另存为文本文件。每个批处理间隔的文件名是根据 _前缀_ 和 _后缀_ : _"prefix-TIME_IN_MS[.suffix]"_ 生成的。 -| **saveAsObjectFiles**(_prefix_, [_suffix_]) | 将此 DStream 的内容另存为序列化 Java 对象的 `SequenceFiles`。每个批处理间隔的文件名是根据 _前缀_ 和 _后缀_ : _"prefix-TIME_IN_MS[.suffix]"_ 生成的. +| **saveAsTextFiles**(_prefix_, [_suffix_]) | 将此 DStream 的内容另存为文本文件。每个批处理间隔的文件名是根据 _前缀_ 和 _后缀_:_"prefix-TIME_IN_MS[.suffix]"_ 生成的。 +| **saveAsObjectFiles**(_prefix_, [_suffix_]) | 将此 DStream 的内容另存为序列化 Java 对象的 `SequenceFiles`。每个批处理间隔的文件名是根据 _前缀_ 和 _后缀_:_"prefix-TIME_IN_MS[.suffix]"_ 生成的. Python API 这在Python API中是不可用的。 -| **saveAsHadoopFiles**(_prefix_, [_suffix_]) | 将此 DStream 的内容另存为 Hadoop 文件。每个批处理间隔的文件名是根据 _前缀_ 和 _后缀_ : _"prefix-TIME_IN_MS[.suffix]"_ 生成的. +| **saveAsHadoopFiles**(_prefix_, [_suffix_]) | 将此 DStream 的内容另存为 Hadoop 文件。每个批处理间隔的文件名是根据 _前缀_ 和 _后缀_:_"prefix-TIME_IN_MS[.suffix]"_ 生成的. Python API 这在Python API中是不可用的。 | **foreachRDD**(_func_) | 对从流中生成的每个 RDD 应用函数 _func_ 的最通用的输出运算符。此功能应将每个 RDD 中的数据推送到外部系统,例如将 RDD 保存到文件,或将其通过网络写入数据库。请注意,函数 _func_ 在运行流应用程序的 driver 进程中执行,通常会在其中具有 RDD 动作,这将强制流式传输 RDD 的计算。 | | | @@ -1274,7 +1274,7 @@ words.foreachRDD(process) ## MLlib 操作 -您还可以轻松使用 [MLlib](ml-guide.html) 提供的机器学习算法。首先,有 streaming 机器学习算法(例如: [Streaming 线性回归](mllib-linear-methods.html#streaming-linear-regression),[Streaming KMeans](mllib-clustering.html#streaming-k-means) 等),其可以同时从 streaming 数据中学习,并将该模型应用于 streaming 数据。除此之外,对于更大类的机器学习算法,您可以离线学习一个学习模型(即使用历史数据),然后将该模型在线应用于流数据.有关详细信息,请参阅 [MLlib指南](ml-guide.html). +您还可以轻松使用 [MLlib](ml-guide.html) 提供的机器学习算法。首先,有 streaming 机器学习算法(例如:[Streaming 线性回归](mllib-linear-methods.html#streaming-linear-regression),[Streaming KMeans](mllib-clustering.html#streaming-k-means) 等),其可以同时从 streaming 数据中学习,并将该模型应用于 streaming 数据。除此之外,对于更大类的机器学习算法,您可以离线学习一个学习模型(即使用历史数据),然后将该模型在线应用于流数据.有关详细信息,请参阅 [MLlib指南](ml-guide.html). * * * @@ -1282,7 +1282,7 @@ words.foreachRDD(process) 与 RDD 类似,DStreams 还允许开发人员将流的数据保留在内存中。也就是说,在 DStream 上使用 `persist()` 方法会自动将该 DStream 的每个 RDD 保留在内存中。如果 DStream 中的数据将被多次计算(例如,相同数据上的多个操作),这将非常有用。对于基于窗口的操作,如 `reduceByWindow` 和 `reduceByKeyAndWindow` 以及基于状态的操作,如 `updateStateByKey`,这是隐含的.因此,基于窗口的操作生成的 DStream 会自动保存在内存中,而不需要开发人员调用 `persist()`. -对于通过网络接收数据(例如: Kafka,Flume,sockets 等)的输入流,默认持久性级别被设置为将数据复制到两个节点进行容错. +对于通过网络接收数据(例如:Kafka,Flume,sockets 等)的输入流,默认持久性级别被设置为将数据复制到两个节点进行容错. 请注意,与 RDD 不同,DStreams 的默认持久性级别将数据序列化在内存中。这在 [性能调优](#memory-tuning) 部分进一步讨论。有关不同持久性级别的更多信息,请参见 [Spark编程指南](programming-guide.html#rdd-persistence). @@ -1412,7 +1412,7 @@ You can also explicitly create a `StreamingContext` from the checkpoint data and 除了使用 `getOrCreate` 之外,还需要确保在失败时自动重新启动 driver 进程。这只能由用于运行应用程序的部署基础架构完成。这在 [部署](#deploying-applications) 部分进一步讨论. -请注意,RDD 的 checkpoint 会导致保存到可靠存储的成本。这可能会导致 RDD 得到 checkpoint 的批次的处理时间增加。因此,需要仔细设置 checkpoint 的间隔。在小批量大小(例如: 1秒),检查每个批次可能会显着降低操作吞吐量。相反,checkpoint 太少会导致谱系和任务大小增长,这可能会产生不利影响。对于需要 RDD checkpoint 的状态转换,默认间隔是至少10秒的批间隔的倍数。它可以通过使用 `dstream.checkpoint(checkpointInterval)` 进行设置。通常,DStream 的5到10个滑动间隔的 checkpoint 间隔是一个很好的设置. +请注意,RDD 的 checkpoint 会导致保存到可靠存储的成本。这可能会导致 RDD 得到 checkpoint 的批次的处理时间增加。因此,需要仔细设置 checkpoint 的间隔。在小批量大小(例如:1秒),检查每个批次可能会显着降低操作吞吐量。相反,checkpoint 太少会导致谱系和任务大小增长,这可能会产生不利影响。对于需要 RDD checkpoint 的状态转换,默认间隔是至少10秒的批间隔的倍数。它可以通过使用 `dstream.checkpoint(checkpointInterval)` 进行设置。通常,DStream 的5到10个滑动间隔的 checkpoint 间隔是一个很好的设置. * * * @@ -1584,7 +1584,7 @@ wordCounts.foreachRDD(echo) * _集群管理器集群_ - 这是任何 Spark 应用程序的一般要求,并在 [部署指南](cluster-overview.html) 中详细讨论. -* _打包应用程序 JAR_ - 您必须将 streaming 应用程序编译为 JAR。如果您正在使用 [`spark-submit`](submitting-applications.html) 启动应用程序,则不需要在 JAR 中提供 Spark 和 Spark Streaming.但是,如果您的应用程序使用高级资源(例如: Kafka,Flume),那么您将必须将他们链接的额外工件及其依赖项打包在用于部署应用程序的 JAR 中.例如,使用 `KafkaUtils` 的应用程序必须在应用程序 JAR 中包含 `spark-streaming-kafka-0-8_2.11` 及其所有传递依赖关系. +* _打包应用程序 JAR_ - 您必须将 streaming 应用程序编译为 JAR。如果您正在使用 [`spark-submit`](submitting-applications.html) 启动应用程序,则不需要在 JAR 中提供 Spark 和 Spark Streaming.但是,如果您的应用程序使用高级资源(例如:Kafka,Flume),那么您将必须将他们链接的额外工件及其依赖项打包在用于部署应用程序的 JAR 中.例如,使用 `KafkaUtils` 的应用程序必须在应用程序 JAR 中包含 `spark-streaming-kafka-0-8_2.11` 及其所有传递依赖关系. * _为 executor 配置足够的内存_ - 由于接收到的数据必须存储在内存中,所以 executor 必须配置足够的内存来保存接收到的数据。请注意,如果您正在进行10分钟的窗口操作,系统必须至少保留最近10分钟的内存中的数据。因此,应用程序的内存要求取决于其中使用的操作. @@ -1604,7 +1604,7 @@ wordCounts.foreachRDD(echo) * 升级后的 Spark Streaming 应用程序与现有应用程序并行启动并运行.一旦新的(接收与旧的数据相同的数据)已经升温并准备好黄金时段,旧的可以被关掉.请注意,这可以用于支持将数据发送到两个目的地(即较早和已升级的应用程序)的数据源. -* 现有应用程序正常关闭(请参阅 [`StreamingContext.stop(...)`](api/scala/index.html#org.apache.spark.streaming.StreamingContext) 或 [`JavaStreamingContext.stop(...)`](api/java/index.html?org/apache/spark/streaming/api/java/JavaStreamingContext.html) 以获取正常的关闭选项),以确保已关闭的数据在关闭之前被完全处理.然后可以启动升级的应用程序,这将从较早的应用程序停止的同一点开始处理.请注意,只有在支持源端缓冲的输入源(如: Kafka 和 Flume)时才可以进行此操作,因为数据需要在先前的应用程序关闭并且升级的应用程序尚未启动时进行缓冲.从升级前代码的早期 checkpoint 信息重新启动不能完成.checkpoint 信息基本上包含序列化的 Scala/Java/Python 对象,并尝试使用新的修改的类反序列化对象可能会导致错误.在这种情况下,可以使用不同的 checkpoint 目录启动升级的应用程序,也可以删除以前的 checkpoint 目录. +* 现有应用程序正常关闭(请参阅 [`StreamingContext.stop(...)`](api/scala/index.html#org.apache.spark.streaming.StreamingContext) 或 [`JavaStreamingContext.stop(...)`](api/java/index.html?org/apache/spark/streaming/api/java/JavaStreamingContext.html) 以获取正常的关闭选项),以确保已关闭的数据在关闭之前被完全处理.然后可以启动升级的应用程序,这将从较早的应用程序停止的同一点开始处理.请注意,只有在支持源端缓冲的输入源(如:Kafka 和 Flume)时才可以进行此操作,因为数据需要在先前的应用程序关闭并且升级的应用程序尚未启动时进行缓冲.从升级前代码的早期 checkpoint 信息重新启动不能完成.checkpoint 信息基本上包含序列化的 Scala/Java/Python 对象,并尝试使用新的修改的类反序列化对象可能会导致错误.在这种情况下,可以使用不同的 checkpoint 目录启动升级的应用程序,也可以删除以前的 checkpoint 目录. * * * @@ -1689,9 +1689,9 @@ unifiedStream.pprint() 可以通过调优 serialization formats (序列化格式)来减少数据 serialization (序列化)的开销.在 streaming 的情况下,有两种类型的数据被 serialized (序列化). -* **Input data (输入数据)**: 默认情况下,通过 Receivers 接收的 input data (输入数据)通过 [StorageLevel.MEMORY_AND_DISK_SER_2](api/scala/index.html#org.apache.spark.storage.StorageLevel$) 存储在 executors 的内存中.也就是说,将数据 serialized (序列化)为 bytes (字节)以减少 GC 开销,并复制以容忍 executor failures (执行器故障).此外,数据首先保留在内存中,并且只有在内存不足以容纳 streaming computation (流计算)所需的所有输入数据时才会 spilled over (溢出)到磁盘.这个 serialization (序列化)显然具有开销 - receiver (接收器)必须使接收的数据 deserialize (反序列化),并使用 Spark 的 serialization format (序列化格式)重新序列化它. +* **Input data (输入数据)**:默认情况下,通过 Receivers 接收的 input data (输入数据)通过 [StorageLevel.MEMORY_AND_DISK_SER_2](api/scala/index.html#org.apache.spark.storage.StorageLevel$) 存储在 executors 的内存中.也就是说,将数据 serialized (序列化)为 bytes (字节)以减少 GC 开销,并复制以容忍 executor failures (执行器故障).此外,数据首先保留在内存中,并且只有在内存不足以容纳 streaming computation (流计算)所需的所有输入数据时才会 spilled over (溢出)到磁盘.这个 serialization (序列化)显然具有开销 - receiver (接收器)必须使接收的数据 deserialize (反序列化),并使用 Spark 的 serialization format (序列化格式)重新序列化它. -* **Persisted RDDs generated by Streaming Operations (流式操作生成的持久 RDDs)**: 通过 streaming computations (流式计算)生成的 RDD 可能会持久存储在内存中.例如,window operations (窗口操作)会将数据保留在内存中,因为它们将被处理多次.但是,与 [StorageLevel.MEMORY_ONLY](api/scala/index.html#org.apache.spark.storage.StorageLevel$) 的 Spark Core 默认情况不同,通过流式计算生成的持久化 RDD 将以 [StorageLevel.MEMORY_ONLY_SER](api/scala/index.html#org.apache.spark.storage.StorageLevel$) (即序列化),以最小化 GC 开销. +* **Persisted RDDs generated by Streaming Operations (流式操作生成的持久 RDDs)**:通过 streaming computations (流式计算)生成的 RDD 可能会持久存储在内存中.例如,window operations (窗口操作)会将数据保留在内存中,因为它们将被处理多次.但是,与 [StorageLevel.MEMORY_ONLY](api/scala/index.html#org.apache.spark.storage.StorageLevel$) 的 Spark Core 默认情况不同,通过流式计算生成的持久化 RDD 将以 [StorageLevel.MEMORY_ONLY_SER](api/scala/index.html#org.apache.spark.storage.StorageLevel$) (即序列化),以最小化 GC 开销. 在这两种情况下,使用 Kryo serialization (Kryo 序列化)可以减少 CPU 和内存开销.有关详细信息,请参阅 [Spark Tuning Guide](tuning.html#data-serialization) .对于 Kryo,请考虑 registering custom classes,并禁用对象引用跟踪(请参阅 [Configuration Guide](configuration.html#compression-and-serialization) 中的 Kryo 相关配置). @@ -1701,7 +1701,7 @@ unifiedStream.pprint() 如果每秒启动的任务数量很高(比如每秒 50 个或更多),那么这个开销向 slaves 发送任务可能是重要的,并且将难以实现 sub-second latencies (次要的延迟).可以通过以下更改减少开销: -* **Execution mode (执行模式)**: 以 Standalone mode (独立模式)或 coarse-grained Mesos 模式运行 Spark 比 fine-grained Mesos 模式更好的任务启动时间.有关详细信息,请参阅 [Running on Mesos guide](running-on-mesos.html) . +* **Execution mode (执行模式)**:以 Standalone mode (独立模式)或 coarse-grained Mesos 模式运行 Spark 比 fine-grained Mesos 模式更好的任务启动时间.有关详细信息,请参阅 [Running on Mesos guide](running-on-mesos.html) . 这些更改可能会将 batch processing time (批处理时间)缩短 100 毫秒,从而允许 sub-second batch size (次秒批次大小)是可行的. @@ -1729,13 +1729,13 @@ memory tuning (内存调优)的另一个方面是 garbage collection (垃 有几个 parameters (参数)可以帮助您调整 memory usage (内存使用量)和 GC 开销: -* **Persistence Level of DStreams (DStreams 的持久性级别)**: 如前面在 [Data Serialization](#data-serialization) 部分中所述,input data 和 RDD 默认保持为 serialized bytes (序列化字节).与 deserialized persistence (反序列化持久性)相比,这减少了内存使用量和 GC 开销.启用 Kryo serialization 进一步减少了 serialized sizes (序列化大小)和 memory usage (内存使用).可以通过 compression (压缩)来实现内存使用的进一步减少(参见Spark配置 `spark.rdd.compress` ),代价是 CPU 时间. +* **Persistence Level of DStreams (DStreams 的持久性级别)**:如前面在 [Data Serialization](#data-serialization) 部分中所述,input data 和 RDD 默认保持为 serialized bytes (序列化字节).与 deserialized persistence (反序列化持久性)相比,这减少了内存使用量和 GC 开销.启用 Kryo serialization 进一步减少了 serialized sizes (序列化大小)和 memory usage (内存使用).可以通过 compression (压缩)来实现内存使用的进一步减少(参见Spark配置 `spark.rdd.compress` ),代价是 CPU 时间. -* **Clearing old data (清除旧数据)**: 默认情况下,DStream 转换生成的所有 input data 和 persisted RDDs 将自动清除。Spark Streaming 决定何时根据所使用的 transformations (转换)来清除数据.例如,如果您使用 10 分钟的 window operation (窗口操作),则 Spark Streaming 将保留最近 10 分钟的数据,并主动丢弃旧数据。数据可以通过设置 `streamingContext.remember` 保持更长的持续时间(例如交互式查询旧数据). +* **Clearing old data (清除旧数据)**:默认情况下,DStream 转换生成的所有 input data 和 persisted RDDs 将自动清除。Spark Streaming 决定何时根据所使用的 transformations (转换)来清除数据.例如,如果您使用 10 分钟的 window operation (窗口操作),则 Spark Streaming 将保留最近 10 分钟的数据,并主动丢弃旧数据。数据可以通过设置 `streamingContext.remember` 保持更长的持续时间(例如交互式查询旧数据). -* **CMS Garbage Collector (CMS垃圾收集器)**: 强烈建议使用 concurrent mark-and-sweep GC,以保持 GC 相关的暂停始终如一.即使 concurrent GC 已知可以减少 系统的整体处理吞吐量,其使用仍然建议实现更多一致的 batch processing times (批处理时间).确保在 driver (使用 `--driver-java-options` 在 `spark-submit` 中 )和 executors (使用 [Spark configuration](configuration.html#runtime-environment) `spark.executor.extraJavaOptions` )中设置 CMS GC. +* **CMS Garbage Collector (CMS垃圾收集器)**:强烈建议使用 concurrent mark-and-sweep GC,以保持 GC 相关的暂停始终如一.即使 concurrent GC 已知可以减少 系统的整体处理吞吐量,其使用仍然建议实现更多一致的 batch processing times (批处理时间).确保在 driver (使用 `--driver-java-options` 在 `spark-submit` 中 )和 executors (使用 [Spark configuration](configuration.html#runtime-environment) `spark.executor.extraJavaOptions` )中设置 CMS GC. -* **Other tips (其他提示)**: 为了进一步降低 GC 开销,以下是一些更多的提示. +* **Other tips (其他提示)**:为了进一步降低 GC 开销,以下是一些更多的提示. * 使用 `OFF_HEAP` 存储级别的保持 RDDs .在 [Spark Programming Guide](programming-guide.html#rdd-persistence) 中查看更多详细信息. * 使用更小的 heap sizes 的 executors.这将降低每个 JVM heap 内的 GC 压力. @@ -1790,27 +1790,27 @@ Spark 运行在容错文件系统(如 HDFS 或 S3 )中的数据上.因此, streaming systems (流系统)的语义通常是通过系统可以处理每个记录的次数来捕获的.系统可以在所有可能的操作条件下提供三种类型的保证(尽管有故障等). -1. _At most once (最多一次)_: 每个 record (记录)将被处理一次或根本不处理. -2. _At least once (至少一次)_: 每个 record (记录)将被处理一次或多次.这比_at-most once_,因为它确保没有数据将丢失.但可能有重复. -3. _Exactly once(有且仅一次)_: 每个 record (记录) 将被精确处理一次 - 没有数据丢失,数据不会被多次处理.这显然是三者的最强保证. +1. _At most once (最多一次)_:每个 record (记录)将被处理一次或根本不处理. +2. _At least once (至少一次)_:每个 record (记录)将被处理一次或多次.这比_at-most once_,因为它确保没有数据将丢失.但可能有重复. +3. _Exactly once(有且仅一次)_:每个 record (记录) 将被精确处理一次 - 没有数据丢失,数据不会被多次处理.这显然是三者的最强保证. ## Basic Semantics (基本语义) 在任何 stream processing system (流处理系统)中,广义上说,处理数据有三个步骤. -1. _Receiving the data (接收数据)_: 使用 Receivers 或其他方式从数据源接收数据. +1. _Receiving the data (接收数据)_:使用 Receivers 或其他方式从数据源接收数据. -2. _Transforming the data (转换数据)_: 使用 DStream 和 RDD transformations 来 transformed (转换)接收到的数据. +2. _Transforming the data (转换数据)_:使用 DStream 和 RDD transformations 来 transformed (转换)接收到的数据. -3. _Pushing out the data (推出数据)_: 最终的转换数据被推出到 external systems (外部系统),如 file systems (文件系统),databases (数据库),dashboards (仪表板)等. +3. _Pushing out the data (推出数据)_:最终的转换数据被推出到 external systems (外部系统),如 file systems (文件系统),databases (数据库),dashboards (仪表板)等. 如果 streaming application 必须实现 end-to-end exactly-once guarantees (端到端的一次且仅一次性保证),那么每个步骤都必须提供 exactly-once guarantee .也就是说,每个记录必须被精确地接收一次,转换完成一次,并被推送到下游系统一次.让我们在 Spark Streaming 的上下文中了解这些步骤的语义. -1. _Receiving the data (接收数据)_: 不同的 input sources 提供不同的保证.这将在下一小节中详细讨论. +1. _Receiving the data (接收数据)_:不同的 input sources 提供不同的保证.这将在下一小节中详细讨论. -2. _Transforming the data (转换数据)_: 所有已收到的数据都将被处理 _exactly once_,这得益于 RDD 提供的保证.即使存在故障,只要接收到的输入数据可访问,最终变换的 RDD 将始终具有相同的内容. +2. _Transforming the data (转换数据)_:所有已收到的数据都将被处理 _exactly once_,这得益于 RDD 提供的保证.即使存在故障,只要接收到的输入数据可访问,最终变换的 RDD 将始终具有相同的内容. -3. _Pushing out the data (推出数据)_: 默认情况下的输出操作确保 _at-least once_ 语义,因为它取决于输出操作的类型( idempotent (幂等))或 downstream system (下游系统)的语义(是否支持 transactions (事务)).但用户可以实现自己的事务机制来实现 _exactly-once_ 语义.这将在本节后面的更多细节中讨论. +3. _Pushing out the data (推出数据)_:默认情况下的输出操作确保 _at-least once_ 语义,因为它取决于输出操作的类型( idempotent (幂等))或 downstream system (下游系统)的语义(是否支持 transactions (事务)).但用户可以实现自己的事务机制来实现 _exactly-once_ 语义.这将在本节后面的更多细节中讨论. ## Semantics of Received Data (接收数据的语义) @@ -1854,9 +1854,9 @@ At-least once semantics (至少一次性语义) | Output operations (输出操作)(如 `foreachRDD` )具有 _at-least once_ 语义,也就是说,transformed data (变换后的数据)可能会不止一次写入 external entity (外部实体)在一个 worker 故障事件中.虽然这是可以接受的使用 `saveAs***Files`操作(因为文件将被相同的数据简单地覆盖) 保存到文件系统,可能需要额外的努力来实现 exactly-once (一次且仅一次)语义.有两种方法. -* _Idempotent updates (幂等更新)_: 多次尝试总是写入相同的数据.例如,`saveAs***Files` 总是将相同的数据写入生成的文件. +* _Idempotent updates (幂等更新)_:多次尝试总是写入相同的数据.例如,`saveAs***Files` 总是将相同的数据写入生成的文件. -* _Transactional updates (事务更新)_: 所有更新都是事务性的,以便更新完全按原子进行.这样做的一个方法如下. +* _Transactional updates (事务更新)_:所有更新都是事务性的,以便更新完全按原子进行.这样做的一个方法如下. * 使用批处理时间(在 `foreachRDD` 中可用)和 RDD 的 partition index (分区索引)来创建 identifier (标识符).该标识符唯一地标识 streaming application 中的 blob 数据. * 使用该 identifier (标识符)blob transactionally (blob 事务地)更新 external system (外部系统)(即,exactly once,atomically (一次且仅一次,原子性地)).也就是说,如果 identifier (标识符)尚未提交,则以 atomically (原子方式)提交 partition data (分区数据)和 identifier (标识符).否则,如果已经提交,请跳过更新. diff --git a/docs/7.md b/docs/7.md index d386894..c5780f5 100644 --- a/docs/7.md +++ b/docs/7.md @@ -4,7 +4,7 @@ * [SQL](#sql) * [Datasets and DataFrames](#datasets-and-dataframes) * [开始入门](#开始入门) - * [起始点: SparkSession](#起始点-sparksession) + * [起始点:SparkSession](#起始点-sparksession) * [创建 DataFrames](#创建-dataframes) * [无类型的Dataset操作 (aka DataFrame 操作)](#无类型的dataset操作-aka-dataframe-操作) * [Running SQL Queries Programmatically](#running-sql-queries-programmatically) @@ -82,13 +82,13 @@ Spark SQL 的功能之一是执行 SQL 查询.Spark SQL 也能够被用于从已 一个 Dataset 是一个分布式的数据集合 Dataset 是在 Spark 1.6 中被添加的新接口,它提供了 RDD 的优点(强类型化,能够使用强大的 lambda 函数)与Spark SQL执行引擎的优点.一个 Dataset 可以从 JVM 对象来 [构造](#creating-datasets) 并且使用转换功能(map,flatMap,filter,等等)。Dataset API 在[Scala](api/scala/index.html#org.apache.spark.sql.Dataset) 和 [Java](api/java/index.html?org/apache/spark/sql/Dataset.html)是可用的.Python 不支持 Dataset API.但是由于 Python 的动态特性,许多 Dataset API 的优点已经可用了 (也就是说,你可能通过 name 天生的`row.columnName`属性访问一行中的字段).这种情况和 R 相似. -一个 DataFrame 是一个 _Dataset_ 组成的指定列.它的概念与一个在关系型数据库或者在 R/Python 中的表是相等的,但是有很多优化。DataFrames 可以从大量的 [sources](#data-sources) 中构造出来,比如: 结构化的文本文件,Hive中的表,外部数据库,或者已经存在的 RDDs。DataFrame API 可以在 Scala,Java,[Python](api/python/pyspark.sql.html#pyspark.sql.DataFrame),和 [R](api/R/index.html)中实现。在 Scala 和 Java中,DataFrame 由 DataSet 中的 `RowS`(多个 Row)来表示。在 [the Scala API](api/scala/index.html#org.apache.spark.sql.Dataset)中,`DataFrame` 仅仅是一个 `Dataset[Row]`类型的别名。然而,在 [Java API](api/java/index.html?org/apache/spark/sql/Dataset.html)中,用户需要去使用 `Dataset<Row>` 去代表一个 `DataFrame`. +一个 DataFrame 是一个 _Dataset_ 组成的指定列.它的概念与一个在关系型数据库或者在 R/Python 中的表是相等的,但是有很多优化。DataFrames 可以从大量的 [sources](#data-sources) 中构造出来,比如:结构化的文本文件,Hive中的表,外部数据库,或者已经存在的 RDDs。DataFrame API 可以在 Scala,Java,[Python](api/python/pyspark.sql.html#pyspark.sql.DataFrame),和 [R](api/R/index.html)中实现。在 Scala 和 Java中,DataFrame 由 DataSet 中的 `RowS`(多个 Row)来表示。在 [the Scala API](api/scala/index.html#org.apache.spark.sql.Dataset)中,`DataFrame` 仅仅是一个 `Dataset[Row]`类型的别名。然而,在 [Java API](api/java/index.html?org/apache/spark/sql/Dataset.html)中,用户需要去使用 `Dataset<Row>` 去代表一个 `DataFrame`. 在此文档中,我们将常常会引用 Scala/Java Datasets 的 `Row`s 作为 DataFrames. # 开始入门 -## 起始点: SparkSession +## 起始点:SparkSession Spark SQL中所有功能的入口点是 [`SparkSession`](api/scala/index.html#org.apache.spark.sql.SparkSession) 类。要创建一个 `SparkSession`,仅使用 `SparkSession.builder()`就可以了: @@ -251,7 +251,7 @@ showDF(df) DataFrames 提供了一个特定的语法用在 [Scala](api/scala/index.html#org.apache.spark.sql.Dataset),[Java](api/java/index.html?org/apache/spark/sql/Dataset.html),[Python](api/python/pyspark.sql.html#pyspark.sql.DataFrame) and [R](api/R/SparkDataFrame.html)中机构化数据的操作. -正如上面提到的一样,Spark 2.0中,DataFrames在Scala 和 Java API中,仅仅是多个 `Row`s的Dataset。这些操作也参考了与强类型的Scala/Java Datasets中的”类型转换” 对应的”无类型转换” . +正如上面提到的一样,Spark 2.0 中,DataFrames 在 Scala 和 Java API 中,仅仅是多个 `Row`s 的 Dataset。这些操作也参考了与强类型的 Scala/Java Datasets 中的 “类型转换” 对应的 “无类型转换” . 这里包括一些使用 Dataset 进行结构化数据处理的示例 : @@ -2085,7 +2085,7 @@ REFRESH TABLE my_table; | `spark.sql.parquet.binaryAsString` | false | 一些其他 Parquet-producing systems (Parquet 生产系统),特别是 Impala,Hive 和旧版本的 Spark SQL,在 writing out (写出) Parquet schema 时,不区分 binary data (二进制数据)和 strings (字符串)。该 flag 告诉 Spark SQL 将 binary data (二进制数据)解释为 string (字符串)以提供与这些系统的兼容性。 | `spark.sql.parquet.int96AsTimestamp` | true | 一些 Parquet-producing systems,特别是 Impala 和 Hive,将 Timestamp 存入INT96。该 flag 告诉 Spark SQL 将 INT96 数据解析为 timestamp 以提供与这些系统的兼容性。 | `spark.sql.parquet.cacheMetadata` | true | 打开 Parquet schema metadata 的缓存。可以加快查询静态数据。 -| `spark.sql.parquet.compression.codec` | snappy | 在编写 Parquet 文件时设置 compression codec (压缩编解码器)的使用。可接受的值包括: uncompressed,snappy,gzip,lzo。 +| `spark.sql.parquet.compression.codec` | snappy | 在编写 Parquet 文件时设置 compression codec (压缩编解码器)的使用。可接受的值包括:uncompressed,snappy,gzip,lzo。 | `spark.sql.parquet.filterPushdown` | true | 设置为 true 时启用 Parquet filter push-down optimization。 | `spark.sql.hive.convertMetastoreParquet` | true | 当设置为 false 时,Spark SQL 将使用 Hive SerDe 作为 parquet tables,而不是内置的支持。 | `spark.sql.parquet.mergeSchema` | false | 当为 true 时,Parquet data source (Parquet 数据源) merges (合并)从所有 data files (数据文件)收集的 schemas,否则如果没有可用的 summary file,则从 summary file 或 random data file 中挑选 schema。 @@ -2566,7 +2566,7 @@ results <- collect(sql("FROM src SELECT key, value")) | Property Name | Meaning | | --- | --- | | `fileFormat` | fileFormat是一种存储格式规范的包,包括 "serde","input format" 和 "output format"。目前我们支持6个文件格式:'sequencefile','rcfile','orc','parquet','textfile'和'avro'。 | -| `inputFormat, outputFormat` | 这两个选项将相应的 "InputFormat" 和 "OutputFormat" 类的名称指定为字符串文字,例如: `org.apache.hadoop.hive.ql.io.orc.OrcInputFormat`。这两个选项必须成对出现,如果您已经指定了 "fileFormat" 选项,则无法指定它们。 | +| `inputFormat, outputFormat` | 这两个选项将相应的 "InputFormat" 和 "OutputFormat" 类的名称指定为字符串文字,例如:`org.apache.hadoop.hive.ql.io.orc.OrcInputFormat`。这两个选项必须成对出现,如果您已经指定了 "fileFormat" 选项,则无法指定它们。 | | `serde` | 此选项指定 serde 类的名称。当指定 `fileFormat` 选项时,如果给定的 `fileFormat` 已经包含 serde 的信息,那么不要指定这个选项。目前的 "sequencefile","textfile" 和 "rcfile" 不包含 serde 信息,你可以使用这3个文件格式的这个选项。 | | `fieldDelim, escapeDelim, collectionDelim, mapkeyDelim, lineDelim` | 这些选项只能与 "textfile" 文件格式一起使用。它们定义如何将分隔的文件读入行。 | @@ -2625,7 +2625,7 @@ bin/spark-shell --driver-class-path postgresql-9.4.1207.jar --jars postgresql-9. | `driver` | 用于连接到此 URL 的 JDBC driver 程序的类名。 | | `partitionColumn, lowerBound, upperBound` | 如果指定了这些选项,则必须指定这些选项。另外,必须指定 `numPartitions`。他们描述如何从多个 worker 并行读取数据时将表给分区。`partitionColumn` 必须是有问题的表中的数字列。请注意,`lowerBound` 和 `upperBound` 仅用于决定分区的大小,而不是用于过滤表中的行。因此,表中的所有行将被分区并返回。此选项仅适用于读操作。 | | `numPartitions` | 在表读写中可以用于并行度的最大分区数。这也确定并发JDBC连接的最大数量。如果要写入的分区数超过此限制,则在写入之前通过调用 `coalesce(numPartitions)` 将其减少到此限制。 | -| `fetchsize` | JDBC 抓取的大小,用于确定每次数据往返传递的行数。这有利于提升 JDBC driver 的性能,它们的默认值较小(例如: Oracle 是 10 行)。该选项仅适用于读取操作。 | +| `fetchsize` | JDBC 抓取的大小,用于确定每次数据往返传递的行数。这有利于提升 JDBC driver 的性能,它们的默认值较小(例如:Oracle 是 10 行)。该选项仅适用于读取操作。 | | `batchsize` | JDBC 批处理的大小,用于确定每次数据往返传递的行数。这有利于提升 JDBC driver 的性能。该选项仅适用于写操作。默认值为 `1000`。 | `isolationLevel` | 事务隔离级别,适用于当前连接。它可以是 `NONE`,`READ_COMMITTED`,`READ_UNCOMMITTED`,`REPEATABLE_READ`,或 `SERIALIZABLE` 之一,对应于 JDBC 连接对象定义的标准事务隔离级别,默认为 `READ_UNCOMMITTED`。此选项仅适用于写操作。请参考 `java.sql.Connection` 中的文档。 | | `truncate` | 这是一个与 JDBC 相关的选项。启用 `SaveMode.Overwrite` 时,此选项会导致 Spark 截断现有表,而不是删除并重新创建。这可以更有效,并且防止表元数据(例如,索引)被移除。但是,在某些情况下,例如当新数据具有不同的模式时,它将无法工作。它默认为 `false`。此选项仅适用于写操作。 | @@ -2897,7 +2897,7 @@ Spark SQL CLI 是在本地模式下运行 Hive 转移服务并执行从命令行 ## 从 Spark SQL 2.1 升级到 2.2 -* Spark 2.1.1 介绍了一个新的配置 key: `spark.sql.hive.caseSensitiveInferenceMode`。它的默认设置是 `NEVER_INFER`,其行为与 2.1.0 保持一致。但是,Spark 2.2.0 将此设置的默认值更改为 “INFER_AND_SAVE”,以恢复与底层文件 schema(模式)具有大小写混合的列名称的 Hive metastore 表的兼容性。使用 `INFER_AND_SAVE` 配置的 value,在第一次访问 Spark 将对其尚未保存推测 schema(模式)的任何 Hive metastore 表执行 schema inference(模式推断)。请注意,对于具有数千个 partitions(分区)的表,模式推断可能是非常耗时的操作。如果不兼容大小写混合的列名,您可以安全地将`spark.sql.hive.caseSensitiveInferenceMode` 设置为 `NEVER_INFER`,以避免模式推断的初始开销。请注意,使用新的默认`INFER_AND_SAVE` 设置,模式推理的结果被保存为 metastore key 以供将来使用。因此,初始模式推断仅发生在表的第一次访问。 +* Spark 2.1.1 介绍了一个新的配置 key:`spark.sql.hive.caseSensitiveInferenceMode`。它的默认设置是 `NEVER_INFER`,其行为与 2.1.0 保持一致。但是,Spark 2.2.0 将此设置的默认值更改为 “INFER_AND_SAVE”,以恢复与底层文件 schema(模式)具有大小写混合的列名称的 Hive metastore 表的兼容性。使用 `INFER_AND_SAVE` 配置的 value,在第一次访问 Spark 将对其尚未保存推测 schema(模式)的任何 Hive metastore 表执行 schema inference(模式推断)。请注意,对于具有数千个 partitions(分区)的表,模式推断可能是非常耗时的操作。如果不兼容大小写混合的列名,您可以安全地将`spark.sql.hive.caseSensitiveInferenceMode` 设置为 `NEVER_INFER`,以避免模式推断的初始开销。请注意,使用新的默认`INFER_AND_SAVE` 设置,模式推理的结果被保存为 metastore key 以供将来使用。因此,初始模式推断仅发生在表的第一次访问。 ## 从 Spark SQL 2.0 升级到 2.1 @@ -2910,7 +2910,7 @@ Spark SQL CLI 是在本地模式下运行 Hive 转移服务并执行从命令行 ## 从 Spark SQL 1.6 升级到 2.0 -* `SparkSession` 现在是 Spark 新的切入点,它替代了老的 `SQLContext` 和 `HiveContext`。注意 : 为了向下兼容,老的 SQLContext 和 HiveContext 仍然保留。可以从 `SparkSession` 获取一个新的 `catalog` 接口 — 现有的访问数据库和表的 API,如 `listTables`,`createExternalTable`,`dropTempView`,`cacheTable` 都被移到该接口。 +* `SparkSession` 现在是 Spark 新的切入点,它替代了老的 `SQLContext` 和 `HiveContext`。注意:为了向下兼容,老的 SQLContext 和 HiveContext 仍然保留。可以从 `SparkSession` 获取一个新的 `catalog` 接口 — 现有的访问数据库和表的 API,如 `listTables`,`createExternalTable`,`dropTempView`,`cacheTable` 都被移到该接口。 * Dataset API 和 DataFrame API 进行了统一。在 Scala 中,`DataFrame` 变成了 `Dataset[Row]` 类型的一个别名,而 Java API 使用者必须将 `DataFrame` 替换成 `Dataset<Row>`。Dataset 类既提供了强类型转换操作(如 `map`,`filter` 以及 `groupByKey`)也提供了非强类型转换操作(如 `select` 和 `groupBy`)。由于编译期的类型安全不是 Python 和 R 语言的一个特性,Dataset 的概念并不适用于这些语言的 API。相反,`DataFrame` 仍然是最基本的编程抽象,就类似于这些语言中单节点 data frame 的概念。 @@ -3043,7 +3043,7 @@ sqlContext.setConf("spark.sql.retainGroupColumns", "false") 此外,隐式转换现在只能使用方法 `toDF` 来增加由 `Product`(即 case classes or tuples)构成的 `RDD`,而不是自动应用。 -当使用 DSL 内部的函数时(现在使用 `DataFrame` API 来替换),用户习惯导入 `org.apache.spark.sql.catalyst.dsl`。相反,应该使用公共的 dataframe 函数 API: `import org.apache.spark.sql.functions._`. +当使用 DSL 内部的函数时(现在使用 `DataFrame` API 来替换),用户习惯导入 `org.apache.spark.sql.catalyst.dsl`。相反,应该使用公共的 dataframe 函数 API:`import org.apache.spark.sql.functions._`. #### 针对 DataType 删除在 org.apache.spark.sql 包中的一些类型别名(仅限于 Scala) @@ -3142,13 +3142,13 @@ Spark SQL 支持绝大部分的 Hive 功能,如: **主要的 Hive 功能** -* Tables 使用 buckets 的 Tables: bucket 是 Hive table partition 中的 hash partitioning。Spark SQL 还不支持 buckets. +* Tables 使用 buckets 的 Tables:bucket 是 Hive table partition 中的 hash partitioning。Spark SQL 还不支持 buckets. **Esoteric Hive 功能** * `UNION` 类型 * Unique join -* Column 统计信息的收集: Spark SQL does not piggyback scans to collect column statistics at the moment and only supports populating the sizeInBytes field of the hive metastore. +* Column 统计信息的收集:Spark SQL does not piggyback scans to collect column statistics at the moment and only supports populating the sizeInBytes field of the hive metastore. **Hive Input/Output Formats** @@ -3160,11 +3160,11 @@ Spark SQL 支持绝大部分的 Hive 功能,如: 有少数 Hive 优化还没有包含在 Spark 中。其中一些(比如 indexes 索引)由于 Spark SQL 的这种内存计算模型而显得不那么重要。另外一些在 Spark SQL 未来的版本中会持续跟踪。 * Block 级别的 bitmap indexes 和虚拟 columns (用于构建 indexes) -* 自动为 join 和 groupBy 计算 reducer 个数 : 目前在 Spark SQL 中,你需要使用 “`SET spark.sql.shuffle.partitions=[num_tasks];`” 来控制 post-shuffle 的并行度. -* 仅 Meta-data 的 query: 对于只使用 metadata 就能回答的查询,Spark SQL 仍然会启动计算结果的任务. -* Skew data flag: Spark SQL 不遵循 Hive 中 skew 数据的标记. -* `STREAMTABLE` hint in join: Spark SQL 不遵循 `STREAMTABLE` hint. -* 对于查询结果合并多个小文件: 如果输出的结果包括多个小文件,Hive 可以可选的合并小文件到一些大文件中去,以避免溢出 HDFS metadata。Spark SQL 还不支持这样. +* 自动为 join 和 groupBy 计算 reducer 个数:目前在 Spark SQL 中,你需要使用 “`SET spark.sql.shuffle.partitions=[num_tasks];`” 来控制 post-shuffle 的并行度. +* 仅 Meta-data 的 query:对于只使用 metadata 就能回答的查询,Spark SQL 仍然会启动计算结果的任务. +* Skew data flag:Spark SQL 不遵循 Hive 中 skew 数据的标记. +* `STREAMTABLE` hint in join:Spark SQL 不遵循 `STREAMTABLE` hint. +* 对于查询结果合并多个小文件:如果输出的结果包括多个小文件,Hive 可以可选的合并小文件到一些大文件中去,以避免溢出 HDFS metadata。Spark SQL 还不支持这样. # 参考 diff --git a/docs/9.md b/docs/9.md index e002c96..963b004 100644 --- a/docs/9.md +++ b/docs/9.md @@ -31,7 +31,7 @@ # 概述 -GraphX 是 Spark 中用于图形和图形并行计算的新组件。在高层次上, GraphX 通过引入一个新的[图形](#property_graph)抽象来扩展 Spark [RDD](api/scala/index.html#org.apache.spark.rdd.RDD) :一种具有附加到每个顶点和边缘的属性的定向多重图形。为了支持图计算,GraphX 公开了一组基本运算符(例如: [subgraph](#structural_operators),[joinVertices](#join_operators) 和 [aggregateMessages](#aggregateMessages) )以及 [Pregel](#pregel) API 的优化变体。此外,GraphX 还包括越来越多的图形[算法](#graph_algorithms) 和 [构建器](#graph_builders),以简化图形分析任务。 +GraphX 是 Spark 中用于图形和图形并行计算的新组件。在高层次上, GraphX 通过引入一个新的[图形](#property_graph)抽象来扩展 Spark [RDD](api/scala/index.html#org.apache.spark.rdd.RDD):一种具有附加到每个顶点和边缘的属性的定向多重图形。为了支持图计算,GraphX 公开了一组基本运算符(例如: [subgraph](#structural_operators),[joinVertices](#join_operators) 和 [aggregateMessages](#aggregateMessages) )以及 [Pregel](#pregel) API 的优化变体。此外,GraphX 还包括越来越多的图形[算法](#graph_algorithms) 和 [构建器](#graph_builders),以简化图形分析任务。 # 入门 @@ -525,7 +525,7 @@ avgAgeOfOlderFollowers.collect.foreach(println(_)) ### Map Reduce Triplets Transition Guide (Legacy) -在早期版本的 GraphX 中,邻域聚合是使用 `mapReduceTriplets` 运算符完成的 : +在早期版本的 GraphX 中,邻域聚合是使用 `mapReduceTriplets` 运算符完成的: @@ -542,7 +542,7 @@ class Graph[VD, ED] { `mapReduceTriplets` 操作符接受用户定义的映射函数,该函数应用于每个三元组,并且可以使用用户定义的缩减函数来生成聚合的_消息_。然而,我们发现返回的迭代器的用户是昂贵的,并且它阻止了我们应用其他优化(例如:局部顶点重新编号)的能力。在 [`aggregateMessages`](api/scala/index.html#org.apache.spark.graphx.Graph@aggregateMessages[A]((EdgeContext[VD,ED,A])⇒Unit,(A,A)⇒A,TripletFields)(ClassTag[A]):VertexRDD[A]) 中,我们引入了 EdgeContext,它暴露了三元组字段,并且还显示了向源和目标顶点发送消息的功能。此外,我们删除了字节码检查,而是要求用户指出三元组中实际需要哪些字段。 -以下代码块使用 `mapReduceTriplets` : +以下代码块使用 `mapReduceTriplets`: @@ -557,7 +557,7 @@ val result = graph.mapReduceTriplets[String](msgFun, reduceFun) -可以使用 `aggregateMessages` :å +可以使用 `aggregateMessages`:å diff --git a/docs/paper.md b/docs/paper.md index 9c47c29..a05fd40 100644 --- a/docs/paper.md +++ b/docs/paper.md @@ -1,8 +1,8 @@ # Spark RDD(Resilient Distributed Datasets)论文 * [概要](#概要) -* [1: 介绍](#1-介绍) -* [2: Resilient Distributed Datasets(RDDs)](#2-resilient-distributed-datasetsrdds) +* [1:介绍](#1-介绍) +* [2:Resilient Distributed Datasets(RDDs)](#2-resilient-distributed-datasetsrdds) * [2.1 RDD 抽象](#21-rdd-抽象) * [2.2 Spark 编程接口](#22-spark-编程接口) * [2.2.1 例子 – 监控日志数据挖掘](#221-例子--监控日志数据挖掘) @@ -40,7 +40,7 @@ 为了能解决程序员能在大规模的集群中以一种容错的方式进行内存计算这个问题,我们提出了 RDDs 的概念。当前的很多框架对迭代式算法场景与交互性数据挖掘场景的处理性能非常差,这个是 RDDs 的提出的动机。如果能将数据保存在内存中,将会使的上面两种场景的性能提高一个数量级。为了能达到高效的容错,RDDs 提供了一种受限制的共享内存的方式,这种方式是基于粗粒度的转换共享状态而非细粒度的更新共享状态。然而,我们分析表明 RDDs 可以表达出很多种类的计算,包括目前专门从事迭代任务的编程计算模型,比如 Pregel,当然也可以表达出目前模型表达不出的计算。我们通过 Spark 系统来实现了 RDDs,并且通过各种各样的用户应用和测试来评估了这个系统. -## 1: 介绍 +## 1:介绍 像 MapReduce 和 Dryad 等分布式计算框架已经广泛应用于大数据集的分析。这些系统可以让用户不用担心分布式工作以及容错,而是使用一系列的高层次的操作 api 来达到并行计算的目的. @@ -60,7 +60,7 @@ 我们通过为基准测试以及用户应用的测试两个方面来评估了 RDDs 和 spark。我们分析显示,Spark 在迭代应用中可以比 hadoop 快上 20 倍以上、使的现实中的数据分析报表的速度提升了 40 倍以及使的交互式的扫1TB数据集的延迟在 5-7 秒。更重要的是,为了彰显 RDDs 的普遍性,我们基于spark 用相对较小的程序(每个包只有 200 行代码)实现了 Pregel 和 HaLoop 的编程模型,包括它们使用的数据分布优化。本篇论文以 RDDs(第二节)和 Spark(第三节)的概述开始。然后在第四节中讨论 了RDD s内部的表达、在第节中讨论了我们的实现以及在第六节中讨论了实验结果。最后,我们讨论了 RDDs 是怎么样来表达现在已存在的几个系统的编程模型(第七节)、调查相关工作(第八节)以及总结. -## 2: Resilient Distributed Datasets(RDDs) +## 2:Resilient Distributed Datasets(RDDs) 这节主要讲述 RDDs 的概要,首先定义 RDDs(2.1)以及介绍 RDDs 在 spark 中的编程接口(2.2),然后对 RDDs 和细粒度共享内存抽象进行的对比(2.3).最后我们讨论了 RDD 模型的限制性. @@ -76,7 +76,7 @@ RDDs 并不要始终被具体化,一个 RDD 有足够的信息知道自己是 Spark 和 DryadLINQ 和 FlumeJava 一样通过集成编程语言 api 来暴露 RDDs,这样的话,每一个数据集就代表一个对象,我们可以调用这个对象中的方法来操作这个对象. -编程者可以通过对稳定存储的数据进行转换操作(即 transformations,比如 map 和 filter 等)来得到一个或者多个 RDDs。然后可以对这些 RDDs 进行 actions 操作,这些操作可以是得到应用的结果值,也可以是将结果数据写入到存储系统中,actions 包括: count(表示返回这个数据集的元素的个数)、collect(表示返回数据集的所有元素)以及 save(表示将输出结果写入到存储系统中)。和 DryadLINQ 一样,spark 在定义 RDDs 的时候并不会真正的计算,而是要等到对这个 RDDs 触发了 actions 操作才会真正的触发计算,这个称之为 RDDs 的 lazy 特性,所以我们可以先对 transformations 进行组装一系列的 pipelines,然后再计算. +编程者可以通过对稳定存储的数据进行转换操作(即 transformations,比如 map 和 filter 等)来得到一个或者多个 RDDs。然后可以对这些 RDDs 进行 actions 操作,这些操作可以是得到应用的结果值,也可以是将结果数据写入到存储系统中,actions 包括:count(表示返回这个数据集的元素的个数)、collect(表示返回数据集的所有元素)以及 save(表示将输出结果写入到存储系统中)。和 DryadLINQ 一样,spark 在定义 RDDs 的时候并不会真正的计算,而是要等到对这个 RDDs 触发了 actions 操作才会真正的触发计算,这个称之为 RDDs 的 lazy 特性,所以我们可以先对 transformations 进行组装一系列的 pipelines,然后再计算. 另外,编程者可以通过调用 RDDs 的 persist 方法来缓存后续需要复用的 RDDs。Spark 默认是将缓存数据放在内存中,但是如果内存不足的话则会写入到磁盘中。用户可以通过 persist 的参数来调整缓存策略,比如只将数据存储在磁盘中或者复制备份数据到多台机器。最后,用户可以为每一个 RDDs 的缓存设置优先级,以达到哪个在内存中的 RDDs 应该首先写道磁盘中 @@ -115,7 +115,7 @@ errors.filter(_.contains("HDFS")) 最后,为了说明我们的模型是如何达到容错的,我们在图一种展示了第三个查询的血缘关系图(lineage graph).在这个查询种,我们以对 lines 进行过滤后的 errors 开始,然后在对 errors 进行了 filter 和 map 操作,最后做了 action 操作即 collect。Spark 会最后两个 transformations 组成一个 pipeline,然后将这个 pipeline 分解成一系列的 task,最后将这些 task 调度到含有 errors 缓存数据的机器上进行执行。此外,如果 errors 的一个分区的数据丢失了,spark 会对 lines 的相对应的分区应用 filter 函数来重新创建 errors 这个分区的数据 ![](img/910ead620fcdc398d7329d58da886e85.jpg) -图一: 我们例子中第三个查询的血缘关系图,其中方框表示 RDDs,箭头表示转换 +图一:我们例子中第三个查询的血缘关系图,其中方框表示 RDDs,箭头表示转换 ### 2.3 RDD 模型的优势 @@ -132,7 +132,7 @@ errors.filter(_.contains("HDFS")) | 计算数据的位置 | 自动的机遇数据本地性 | 取决于app (runtime是以透明为目标的) | | 内存不足时的行为 | 和已经存在的数据流处理系统一样,写磁盘 | 非常糟糕的性能(需要内存的交换?) | -表一: RDDs 和 Distributed shared memory 对比 +表一:RDDs 和 Distributed shared memory 对比 RDDs 只能通过粗粒度的转换被创建(或者被写),然而 DSM 允许对每一个内存位置进行读写,这个是 RDDs 和 DSM 最主要的区别。这样使都 RDDs在 应用中大量写数据受到了限制,但是可以使的容错变的更加高效。特别是,RDDs 不需要发生非常耗时的 checkpoint 操作,因为它可以根据 lineage 进行恢复数据。而且,只有丢掉了数据的分区才会需要重新计算,并不需要回滚整个程序,并且这些重新计算的任务是在多台机器上并行运算的. @@ -151,9 +151,9 @@ Spark 使用 scala 语言实现了抽象的 RDD,scala 是建立在 java VM 上 开发员需要写连接集群中的 workers 的 driver 程序来使用 spark,就比如图 2 展示的。Driver 端程序定义了一系列的 RDDs 并且调用了 RDD 的 action 操作。Driver 的程序同时也会跟踪 RDDs 之间的的血缘关系。workers 是可以将 RDD 分区数据存储在内存中的长期存活的进程. ![](img/96ce3150aa3beb9e3616ca1e9ca97ddb.jpg) -图二: 这个是 Spark 运行时的图,用户写的 driver 端程序启动多个 workers,这些 workers 可以从分布书的存储系统中读取数据块并且可以将计算出来的 RDD 分区数据存放在内存中. +图二:这个是 Spark 运行时的图,用户写的 driver 端程序启动多个 workers,这些 workers 可以从分布书的存储系统中读取数据块并且可以将计算出来的 RDD 分区数据存放在内存中. -在 2.2.1 小节中的日志挖掘例子中,我们提到,用户提供给 RDD 操作比如 map 以参数作为这个操作的闭包(说白了就是函数)。Scala 将这些函数看作一个 java 对象,这些对象是可以序列化的,并且可以通过网络传输传输到其他的机器节点上的。Scala 将函数中的变量看作一个对象中的变量。比如,我们可以写一段这样的代码: var x = 5; rdd.map(_ + 5)来达到给这个 RDD 每一个元素加上 5 的目的. +在 2.2.1 小节中的日志挖掘例子中,我们提到,用户提供给 RDD 操作比如 map 以参数作为这个操作的闭包(说白了就是函数)。Scala 将这些函数看作一个 java 对象,这些对象是可以序列化的,并且可以通过网络传输传输到其他的机器节点上的。Scala 将函数中的变量看作一个对象中的变量。比如,我们可以写一段这样的代码:var x = 5; rdd.map(_ + 5)来达到给这个 RDD 每一个元素加上 5 的目的. RDDs 是被一元素类型参数化的静态类型对象,比如,RDD[Int] 表示一个类型为整数的 RDD。然而,我们很多例子中的 RDD 都会省去这个类型,这个是因为 scala 支持类型推断. @@ -164,7 +164,7 @@ RDDs 是被一元素类型参数化的静态类型对象,比如,RDD[Int] 表 表 2 中列举了 Spark 中 RDD 常用的 transformations 和 actions 操作,且描述了每一个方法的签名以及类型.我们需要记住 transformations 是用来定义一个新的 RDD 的 lazy 操作,而actions 是真正触发一个能返回结果或者将结果写到文件系统中的计算. ![](img/1b873942004f2baa0be7baf802ddaa95.jpg) -表二: Spark 中 RDD 常用的 transformations 和 actions 操作.Seq[T] 表示元素类型为 T 的一个列表. +表二:Spark 中 RDD 常用的 transformations 和 actions 操作.Seq[T] 表示元素类型为 T 的一个列表. 需要注意的是,一些操作比如 join 只适合用于 key-value 类型的 RDDs。我们取的函数的名称和 scala 或者其他函数式编程语言的函数名是一致的。比如,map 是一个 one-to-one 的映射操作,而 flatMap 的每一个输入值会对应一个或者更多的输出值(有点像 MapReduce 中的 map) @@ -201,7 +201,7 @@ RDDs 是被一元素类型参数化的静态类型对象,比如,RDD[Int] 表 在抽象 RDDs 的过程中,怎么表达出 RDDs 能跟踪很多的 transformations 操作之间血缘关系是一个比较大的挑战。理想的情况下,一个实现 RDDs 系统应该是尽可能多的提供 transformations 操作(比如表二中的操作),并且可以让用户以任意的方式来组合这些 transformations 操作。我们提出了基于图的 RDDs 展现方式来达到以上的目的。我们在 spark 中利用这种展现方式达到了在不需要给调度系统为每一个 transformation 操作增加任何的特殊逻辑就可以支持大量的 transformations 操作,这样极大的简化了我们的系统设计. -概括的说,以下五个信息可以表达 RDDs: 一个分区列表,每一个分区就是数据集的原子块。一个父亲 RDDs 的依赖列表。一个计算父亲的数据集的函数。分区模式的元数据信息以及数据存储信息。比如,基于一个 HDFS 文件创建出来的的 RDD 中文件的每一个数据块就是一个分区,并且这个 RDD 知道每一个数据块存储在哪些机器上,同时,在这个 RDD 上进行 map 操作后的结果有相同的分区数,当计算元素的时候,将 map 函数应用到父亲 RDD 数据中的。我们在表三总结了这些接口: +概括的说,以下五个信息可以表达 RDDs:一个分区列表,每一个分区就是数据集的原子块。一个父亲 RDDs 的依赖列表。一个计算父亲的数据集的函数。分区模式的元数据信息以及数据存储信息。比如,基于一个 HDFS 文件创建出来的的 RDD 中文件的每一个数据块就是一个分区,并且这个 RDD 知道每一个数据块存储在哪些机器上,同时,在这个 RDD 上进行 map 操作后的结果有相同的分区数,当计算元素的时候,将 map 函数应用到父亲 RDD 数据中的。我们在表三总结了这些接口: | 操作接口 | 含义 | | --- | --- | @@ -211,9 +211,9 @@ RDDs 是被一元素类型参数化的静态类型对象,比如,RDD[Int] 表 | iterator(p, parentIters) | 根据父亲分区的数据输入计算分区p的所有数据 | | partitioner() | 返回这个RDD是hash还是range分区的元数据信息 | -表三: Spark 中表达 RDDs 的接口 +表三:Spark 中表达 RDDs 的接口 -在设计如何表达 RDDs 之间依赖的接口是一个非常有意思的问题。我们发现将依赖定义成两种类型就足够了: 窄依赖,表示父亲 RDDs 的一个分区最多被子 RDDs 一个分区所依赖。宽依赖,表示父亲 RDDs 的一个分区可以被子 RDDs 的多个子分区所依赖。比如,map 操作是一个窄依赖,join 操作是一个宽依赖操作(除非父亲 RDDs 已经被 hash 分区过),图四显示了其他的例子: +在设计如何表达 RDDs 之间依赖的接口是一个非常有意思的问题。我们发现将依赖定义成两种类型就足够了:窄依赖,表示父亲 RDDs 的一个分区最多被子 RDDs 一个分区所依赖。宽依赖,表示父亲 RDDs 的一个分区可以被子 RDDs 的多个子分区所依赖。比如,map 操作是一个窄依赖,join 操作是一个宽依赖操作(除非父亲 RDDs 已经被 hash 分区过),图四显示了其他的例子: ![](img/b628fdf77e55879809e92a76b54ca363.jpg) 图四:窄依赖和宽依赖的例子.每一个方框表示一个 RDD,带有颜色的矩形表示分区 @@ -222,17 +222,17 @@ RDDs 是被一元素类型参数化的静态类型对象,比如,RDD[Int] 表 Spark 中的这些 RDDs 的通用接口使的实现很多 transformations 操作的时候只花了少于 20 行的代码。实际上,新的 spark 用户可以在不了解调度系统的细节之上来实现新的 transformations 操作(比如,采样和各种 join 操作)。下面简要的概括了一些 RDD 的实现: -* HDFS files: 抽样的输入 RDDs 是 HDFS 中的文件.对于这些 RDDs,partitions 返回文件中每一个数据块对应的一个分区信息(数据块的位置信息存储在 Partition 对象中),preferredLocations 返回每一个数据块所在的机器节点信息,最后 iterator 负责数据块的读取操作. -* map: 对任意的 RDDs 调用 map 操作将会返回一个 MappedRDD 对象.这个对象含有和其父亲 RDDs 相同的分区信息和数据存储节点信息,但是在 iterator 中对父亲的所有输出数据记录应用传给 map 的函数. -* union: 对两个 RDDs 调用 union 操作将会返回一个新的 RDD,这个 RDD 的分区数是他所有父亲 RDDs 的所有分区数的总数.每一个子分区通过相对应的窄依赖的父亲分区计算得到. -* sample: sampling 和 mapping 类似,除了 sample RDD 中为每一个分区存储了一个随机数,作为从父亲分区数据中抽样的种子. -* join: 对两个 RDDs 进行 join 操作,可能导致两个窄依赖(如果两个 RDDs 都是事先经过相同的 hash/range 分区器进行分区),或者导致两个宽依赖,或者一个窄依赖一个宽依赖(一个父亲 RDD 经过分区而另一个没有分区).在上面所有的恶场景中,join 之后的输出 RDD 会有一个 partitioner (从父亲 RDD 中继承过来的或者是一个默认的 hash partitioner). +* HDFS files:抽样的输入 RDDs 是 HDFS 中的文件.对于这些 RDDs,partitions 返回文件中每一个数据块对应的一个分区信息(数据块的位置信息存储在 Partition 对象中),preferredLocations 返回每一个数据块所在的机器节点信息,最后 iterator 负责数据块的读取操作. +* map:对任意的 RDDs 调用 map 操作将会返回一个 MappedRDD 对象.这个对象含有和其父亲 RDDs 相同的分区信息和数据存储节点信息,但是在 iterator 中对父亲的所有输出数据记录应用传给 map 的函数. +* union:对两个 RDDs 调用 union 操作将会返回一个新的 RDD,这个 RDD 的分区数是他所有父亲 RDDs 的所有分区数的总数.每一个子分区通过相对应的窄依赖的父亲分区计算得到. +* sample:sampling 和 mapping 类似,除了 sample RDD 中为每一个分区存储了一个随机数,作为从父亲分区数据中抽样的种子. +* join:对两个 RDDs 进行 join 操作,可能导致两个窄依赖(如果两个 RDDs 都是事先经过相同的 hash/range 分区器进行分区),或者导致两个宽依赖,或者一个窄依赖一个宽依赖(一个父亲 RDD 经过分区而另一个没有分区).在上面所有的恶场景中,join 之后的输出 RDD 会有一个 partitioner (从父亲 RDD 中继承过来的或者是一个默认的 hash partitioner). ## 5 实现 我们用了 14000 行 scala 代码实现了 spark。Spark 系统跑在集群管理者 mesos 上,这样可以使的它和其他的应用比如 hadoop 、 MPI 等共享资源,每一个 spark 程序都是由它的 driver 和 workers 组成,这些 driver 和 workers 都是以一个 mesos 应用运行在 mesos 上的,mesos 可以管理这些应用之间的资源共享问题. -Spark 可以利用已经存在的 hadoop 的 api 组件读取任何的 hadoop 的输入数据源(比如: HDFS 和 Hbase 等),这个程序 api 是运行在没有更改的 scala 版本上. +Spark 可以利用已经存在的 hadoop 的 api 组件读取任何的 hadoop 的输入数据源(比如:HDFS 和 Hbase 等),这个程序 api 是运行在没有更改的 scala 版本上. 我们会简要的概括下几个比较有意思的技术点:我们的 job 调度器( 5.1 节),可以用于交互的 spark 解释器( 5.2 节),内存管理( 5.3 节)以及对 checkpointing 的支持( 5.4 节). @@ -242,7 +242,7 @@ spark 的调度器依赖我们在第 4 章中讨论的 RDDs 的表达. 从总体上看,我们的调度系统有点和 Dryad 相似,但是它还考虑了被存储的 RDDs 的哪些分区还在内存中.当一个用户对某个 RDD 调用了 action 操作(比如 count 或者 save )的时候调度器会检查这个 RDD 的血缘关系图,然后根据这个血缘关系图构建一个含有 stages 的有向无环图( DAG ),最后按照步骤执行这个 DAG 中的 stages,如图 5 的说明.每一个 stage 包含了尽可能多的带有窄依赖的 transformations 操作。这个 stage 的划分是根据需要 shuffle 操作的宽依赖或者任何可以切断对父亲 RDD 计算的某个操作(因为这些父亲 RDD 的分区已经计算过了)。然后调度器可以调度启动 tasks 来执行没有父亲 stage 的 stage (或者父亲 stage 已经计算好了的 stage ),一直到计算完我们的最后的目标 RDD . -![](img/9a1ca367603942cde5c30e70396e8fa3.jpg) 图五: 怎么计算 spark job stage 的例子.实现的方框表示 RDDs ,带有颜色的方形表示分区,黑色的是表示这个分区的数据存储在内存中,对 RDD G 调用 action 操作,我们根据宽依赖生成很多 stages,且将窄依赖的 transformations 操作放在 stage 中.在这个场景中,stage 1 的输出结果已经在内存中,所以我们开始运行 stage 2,然后是 stage 3. +![](img/9a1ca367603942cde5c30e70396e8fa3.jpg) 图五:怎么计算 spark job stage 的例子.实现的方框表示 RDDs ,带有颜色的方形表示分区,黑色的是表示这个分区的数据存储在内存中,对 RDD G 调用 action 操作,我们根据宽依赖生成很多 stages,且将窄依赖的 transformations 操作放在 stage 中.在这个场景中,stage 1 的输出结果已经在内存中,所以我们开始运行 stage 2,然后是 stage 3. 我们调度器在分配 tasks 的时候是采用延迟调度来达到数据本地性的目的(说白了,就是数据在哪里,计算就在哪里)。如果某个分区的数据在某个节点上的内存中,那么将这个分区的计算发送到这个机器节点中。如果某个 RDD 为它的某个分区提供了这个数据存储的位置节点,则将这个分区的计算发送到这个节点上. @@ -260,7 +260,7 @@ Scala 解释器通常是将用户输入的每一行代码编译成一个类, 我们对 spark 中的解释器做了如下两个改变: -1. Class shipping: 为了让 worker 节点能拿到用户输入的每一行代码编译成的 class 的二进制代码,我们使的解释器为这些 classes 的二进制代码提供 HTTP 服务. +1. Class shipping:为了让 worker 节点能拿到用户输入的每一行代码编译成的 class 的二进制代码,我们使的解释器为这些 classes 的二进制代码提供 HTTP 服务. 2. 修改了代码生成:正常情况下,我们通过访问对应的类的静态方法来达到访问将用户输入每一行代码编译成的单例对象.这个以为着,当我们将一个含有在前面行中定义的变量(比如上面例子中的 Line 1.x )的闭包序列化发送到 worker 节点的时候,java 是不会通过对象图来跟踪含有 x 的实力 Line 1 的,这样的话 worker 节点将收不到变量 x.我们修改了代码生成逻辑来达到能直接引用每一行代码生成的实例. 图六显示了经过我们的改变后,解释器是如何将用户输入的一系列的代码转换成 java 对象. @@ -314,7 +314,7 @@ spark 目前提供了一个 checkpointing 的 api ( persist 中的标识为 RE ![](img/f7825d58d347fcf078aa4696b00e2a0b.jpg) 图八: hadoop 、 hadoopBinMem 以及 spark 在随后的迭代花的时间,都是处理 100 G 的数据 -**理解为什么提速了**: 我们惊奇的发现 spark 甚至比基于内存存储二进制数据的 hadoopBinMem 还要快 20 倍。在 hadoopBinMem 中,我们使用的是 hadoop 标准的二进制文件格式( sequenceFile )和 256 m 这么大的数据块大小,以及我们强制将 hadoop 的数据目录放在一个内存的文件系统中。然而,Hadoop 仍然因为下面几点而比 spark 慢: +**理解为什么提速了**:我们惊奇的发现 spark 甚至比基于内存存储二进制数据的 hadoopBinMem 还要快 20 倍。在 hadoopBinMem 中,我们使用的是 hadoop 标准的二进制文件格式( sequenceFile )和 256 m 这么大的数据块大小,以及我们强制将 hadoop 的数据目录放在一个内存的文件系统中。然而,Hadoop 仍然因为下面几点而比 spark 慢: 1. Hadoop 软件栈的最低开销. 2. HDFS 提供数据服务的开销. @@ -348,7 +348,7 @@ spark 目前提供了一个 checkpointing 的 api ( persist 中的标识为 RE 在目前为止,我们都是假设集群中的每一台机器都是有足够的内存来存储迭代之间的 RDDs 的数据的。当没有足够的内存来存储任务的数据的时候 spark 是怎么运行的呢? 在这个实验中,我们给 spark 每一个节点配置很少的内存,这些内存不足以存储的下 RDDs。我们在图十二中,我们展示了不同存储空间下的运行线性回归应用需要的时间。可以看出,随着空间的减少,性能速度慢慢的下降: -![](img/27aa23294584c421c9370d330145a271.jpg) 图十二: 每次都是使用不同的内存,然后在 25 台机器中对 100 GB 的数据运行线性回归的性能对比图 +![](img/27aa23294584c421c9370d330145a271.jpg) 图十二:每次都是使用不同的内存,然后在 25 台机器中对 100 GB 的数据运行线性回归的性能对比图 ### 6.5 用 spark 构建的用户应用 @@ -374,14 +374,14 @@ spark 目前提供了一个 checkpointing 的 api ( persist 中的标识为 RE 对于到目前为止很多独立提出的编程模型,RDDs 都可以高效的表达出来。这里所说的 “高效”,不仅仅是指使用 RDDs 的输出结果和独立提出的编程模型狂简的输出结果是一致的,而且 RDDs 在优化性能方面比这些框架还要强大,比如将特定的数据保存在内存中、对数据分区以减少网络传输以及高效的从错误中恢复。可以用 RDDs 表达的模型如下: -* MapReduce: 可以利用 spark 中的 flatMap 和 groupByKey 操作来表达这个模型,或者如果需要聚合的话可以使用 reduceByKey . -* DryadLINQ: DryadLINQ 系统比 MapReduce 更多的操作,但是这些操作都是直接和 RDD 的转换操作( map,groupByKey,join 等)对应的批量操作. -* SQL: 和 DryadLINQ 一样,SQL 查询都是对一个数据集进行并行的操作计算. -* Pregel: Google 的 Pregel 是一个专门解决迭代图计算应用的模型,它一开始看起来和面向数据集的编程模型的其他系统完全不同.在 Pregel 中,一个程序运行一些列的相互协调的“ supersteps ”.在每一个 superstep 上,对图上的每一个顶点运行用户自定义的函数来更新这个顶点的相关的状态、改变图的拓扑结构以及向其他顶点发送下一个 superstep 需要的消息.这种模型可以表达非常多的图计算算法,包括最短路径、二部图匹配以及 PageRank. +* MapReduce:可以利用 spark 中的 flatMap 和 groupByKey 操作来表达这个模型,或者如果需要聚合的话可以使用 reduceByKey . +* DryadLINQ:DryadLINQ 系统比 MapReduce 更多的操作,但是这些操作都是直接和 RDD 的转换操作( map,groupByKey,join 等)对应的批量操作. +* SQL:和 DryadLINQ 一样,SQL 查询都是对一个数据集进行并行的操作计算. +* Pregel:Google 的 Pregel 是一个专门解决迭代图计算应用的模型,它一开始看起来和面向数据集的编程模型的其他系统完全不同.在 Pregel 中,一个程序运行一些列的相互协调的“ supersteps ”.在每一个 superstep 上,对图上的每一个顶点运行用户自定义的函数来更新这个顶点的相关的状态、改变图的拓扑结构以及向其他顶点发送下一个 superstep 需要的消息.这种模型可以表达非常多的图计算算法,包括最短路径、二部图匹配以及 PageRank. Pregel 在每一次迭代中都是对所有顶点应用相同的用户定义的函数,这个是使的我们用 RDDs 来实现这个模型的关键点。因此,每次迭代后,我们都可以将顶点的状态保存在 RDD 中,然后执行一个批量转换操作( apply )来应用这个函数以及生成一个消息的 RDD。然后我们可以用这个 RDD 通顶点的状态进行 join 来完成消息的交换。和 Pregel 一样,RDDs 允许将点的状态保存在内存中、控制它们的分区以减少网络通讯以及指出从失败中恢复。我们在 spark 上用了 200 行代码的包实现了 Pregel,读者可以参考第 33 个文献来了解更多的细节 -* 迭代 MapReduce: 最近提出的几个系统,包括 HaLoop 和 Twister,它们提供了可以让用户循环跑一系列的 MapReduce 任务的迭代式 MapReduce 模型.这些系统在迭代之间保持数据分区一致,Twister 也可以将数据保存在内存中。RDDs 可以很简单的表达以上两个优化,而且我们基于 spark 花了 200 行代码实现了 HaLoop. +* 迭代 MapReduce:最近提出的几个系统,包括 HaLoop 和 Twister,它们提供了可以让用户循环跑一系列的 MapReduce 任务的迭代式 MapReduce 模型.这些系统在迭代之间保持数据分区一致,Twister 也可以将数据保存在内存中。RDDs 可以很简单的表达以上两个优化,而且我们基于 spark 花了 200 行代码实现了 HaLoop. * 批量流处理: 研究人员最近提出了一些增量处理系统,这些系统是为定期接受新数据然后根据数据更新结果的应用服务的.比如,一个应用需要实时接收新数据,然后每 15 分钟就将接收到的数据和前面 15 分钟的时间窗口的数据进行 join 聚合,将聚合的结果更新到统计数据中.这些系统执行和 Dryad 类似的批处理,但是它们将应用的状态数据存储在分布式系统中.将中间结果放在 RDDs 中可以提高处理速度. * 阐释 RDDs 的表达力为什么这么丰富:为什么 RDDs 可以表达多种多样编程模型?原因就是 RDDs 的限制性对很多并行计算的应用的影响是很小的.特别指出的是,虽然 RDDs 只能通过批量转换而得到,但是很多的并行计算的程序都是将相同的操作应用到大量的数据条目中,这样使的 RDDs 的表达力变的丰富.类似的,RDDs 的不变性并不是障碍,因为我们可以创建多个 RDDs 来表达不同版本的相同数据集.事实上,现在很多的 MapReduce 的应用都是运行在不能对文件修改数据的文件系统中,比如 HDFS. @@ -407,13 +407,13 @@ Pregel 在每一次迭代中都是对所有顶点应用相同的用户定义的 最后,一些系统暴露共享可变状态以使的用户可以执行内存计算。比如,Piccolo 使的用户通过分布式的函数来读取和更新分布式 hash 表中的单元格数据。DSM 和像 RAMCloud 这样的 key - value 存储系统提供了类似的模型。RDDs 和这些系统有两个方面的不同,第一,RDDs 基于像 map,sot 以及 join 等操作提供了高层的编程接口,然而,在 Piccolo 和 DSM 中的接口只是读取和更新表的单元格数据。第二,Piccolo 和 DSM 通过 checkpoint 和回滚机制实现容错,在许多应用中这种机制比机遇血缘机制的 RDDs 的容错的成本更大。最后,如 2.3 小节讨论的,相对于 DSM,RDDs 还提供了其他的优势功能,比如执行慢的 task 的处理机制 -**缓存系统**: Nectar 可以通过标识通用的程序分析的子表达式来达到在 DryadLINQ 任务之间对中间数据结果的复用。这种能力肯定会加入到基于 RDD 的系统中。然而,Nectar 即没有提供基于内存的缓存(他是将数据放到分布式文件系统中)也不能让用户可以显式的对数据集进行缓存控制和分区控制。Ciel 和 FlumeJava 同样可以缓存任务结果,但是也不提供基于内存的缓存或者显式的控制哪些数据可以缓存 +**缓存系统**:Nectar 可以通过标识通用的程序分析的子表达式来达到在 DryadLINQ 任务之间对中间数据结果的复用。这种能力肯定会加入到基于 RDD 的系统中。然而,Nectar 即没有提供基于内存的缓存(他是将数据放到分布式文件系统中)也不能让用户可以显式的对数据集进行缓存控制和分区控制。Ciel 和 FlumeJava 同样可以缓存任务结果,但是也不提供基于内存的缓存或者显式的控制哪些数据可以缓存 Ananthanarayanan et al 已经提出在分布式文件系统上加一层基于内存的缓存来利用数据访问的暂时性和本地性。这种解决方案却是加快了已经存在于文件系统中的数据访问速度,但是它在共享同一个应用中的中间结果方面并没有 RDD 高效,因为它在每一个 stage 之间仍然需要将数据写入到文件系统中 **血缘**:在科学计算以及数据库中,捕获数据的血缘或者来源信息是一个很长时间被研究的话题了,对于像解释结果的应用,需要让他们可以从其他的应用重新产生,且当在工作流中存在一个 bug 或者数据丢失的时候可以重新对数据进行计算。对于这边面的容错的工作,我们推荐读者看第 [5] 和 [9]的资料。RDDs 提供了一种并行编程模型,记录跟踪细粒度的血缘的成本很低,我们可以根据血缘来达到容错的目的. -我们基于血缘的容错机制和 MapReduce 以及 Dryad 一个任务中的容错机制是类似的,在 DAG 中跟踪任务的依赖。然而,在这些系统中,一个任务结束后血缘信息也就丢失了,用户需要依靠数据备份式的存储系统来共享任务之间的数据。与此相反,RDDs 可以在任务之间通过将数据存储在内存中达到高效的数据共享,并不需要数据的备份和磁盘的 I/O 关系型数据库: RDDs 在概念上和数据库中的视图比较类似,存储的 RDDs 则像具体的视图。然而,像 DSM 系统,数据库一般允许细粒度的对所有的数据进行读写访问,这种方式需要对操作和数据进行记录日志,用于容错,以及需要额外的开销来保持数据的一致性,对于粗粒度转换模型的 RDDs 来说,这些额外的开销式不需要的. +我们基于血缘的容错机制和 MapReduce 以及 Dryad 一个任务中的容错机制是类似的,在 DAG 中跟踪任务的依赖。然而,在这些系统中,一个任务结束后血缘信息也就丢失了,用户需要依靠数据备份式的存储系统来共享任务之间的数据。与此相反,RDDs 可以在任务之间通过将数据存储在内存中达到高效的数据共享,并不需要数据的备份和磁盘的 I/O 关系型数据库:RDDs 在概念上和数据库中的视图比较类似,存储的 RDDs 则像具体的视图。然而,像 DSM 系统,数据库一般允许细粒度的对所有的数据进行读写访问,这种方式需要对操作和数据进行记录日志,用于容错,以及需要额外的开销来保持数据的一致性,对于粗粒度转换模型的 RDDs 来说,这些额外的开销式不需要的. ## 9 结尾 -- GitLab