【注】该系列文章以及使用到安装包/测试数据 可以在《 倾情大奉送--Spark入门实战系列 》获取
Spark 可以通过 SBT 和 Maven 两种方式进行编译,再通过 make-distribution.sh 脚本生成部署包。 SBT 编译需要安装 git 工具,而 Maven 安装则需要 maven 工具,两种方式均需要在联网下进行,通过比较发现 SBT 编译速度较慢(原因有可能是 1 、时间不一样, SBT 是白天编译, Maven 是深夜进行的,获取依赖包速度不同 2 、 maven 下载大文件是多线程进行,而 SBT 是单进程), Maven 编译成功前后花了 3 、 4 个小时。
1. 从如下地址下载 git 安装包
http://www.onlinedown.net/softdown/169333_2.htm
https://www.kernel.org/pub/software/scm/git/
如果 linux 是 CentOS 操作系统可以通过: yum install git 直接进行安装
由于从 https 获取内容,需要安装 curl-devel ,可以从如下地址获取
http://rpmfind.net/linux/rpm2html/search.php?query=curl-devel
如果 linux 是 CentOS 操作系统可以通过: yum install curl-devel 直接进行安装
2. 上传 git 并解压缩
把 git-1.7.6.tar.gz 安装包上传到 /home/hadoop/upload 目录中,解压缩然后放到 /app 目录下
$cd /home/hadoop/upload/
$tar -xzf git-1.7.6.tar.gz
$mv git-1.7.6 /app
$ll /app
3. 编译安装 git
以 root 用户进行在 git 所在路径编译安装 git
#yum install curl-devel
#cd /app/git-1.7.6
#./configure
#make
#make install
4. 把 git 加入到 PATH 路径中
打开 /etc/profile 把 git 所在路径加入到 PATH 参数中
export GIT_HOME=/app/git-1.7.6
export PATH=$PATH:$JAVA_HOME/bin:$MAVEN_HOME/bin:$GIT_HOME/bin
重新登录或者使用 source /etc/profile 使参数生效,然后使用 git 命令查看配置是否正确
1. 可以从如下地址下载到 spark 源代码:
http://spark.apache.org/downloads.html
http://d3kbcqa49mib13.cloudfront.net/spark-1.1.0.tgz
git clone https://github.com/apache/spark.git
把下载好的 spark-1.1.0.tgz 源代码包使用 1.1.3.1 介绍的工具上传到 /home/hadoop/upload 目录下
2. 在主节点上解压缩
$cd /home/hadoop/upload/
$tar -xzf spark-1.1.0.tgz
3. 把 spark-1.1.0 改名并移动到 /app/complied 目录下
$mv spark-1.1.0 /app/complied/spark-1.1.0-sbt
$ls /app/complied
编译 spark 源代码的时候,需要从网上下载依赖包,所以整个编译过程机器必须保证在联网状态。编译执行如下脚本:
$cd /app/complied/spark-1.1.0-sbt
$sbt/sbt assembly -Pyarn -Phadoop-2.2 -Pspark-ganglia-lgpl -Pkinesis-asl -Phive
整个编译过程编译了约十几个任务,重新编译 N 次,需要几个甚至十几个小时才能编译完成(主要看下载依赖包的速度)。
在编译前最好安装 3.0 以上版本的 Maven ,在 /etc/profile 配置文件中加入如下设置:
export MAVEN_HOME=/app/apache-maven-3.0.5
export PATH=$PATH:$JAVA_HOME/bin:$MAVEN_HOME/bin:$GIT_HOME/bin
1. 可以从如下地址下载到 spark 源代码:
http://spark.apache.org/downloads.html
http://d3kbcqa49mib13.cloudfront.net/spark-1.1.0.tgz
git clone https://github.com/apache/spark.git
把下载好的 spark-1.1.0.tgz 源代码包使用 1.1.3.1 介绍的工具上传到 /home/hadoop/upload 目录下
2. 在主节点上解压缩
$cd /home/hadoop/upload/
$tar -xzf spark-1.1.0.tgz
3. 把 spark-1.1.0 改名并移动到 /app/complied 目录下
$mv spark-1.1.0 /app/complied/spark-1.1.0-mvn
$ls /app/complied
编译 spark 源代码的时候,需要从网上下载依赖包,所以整个编译过程机器必须保证在联网状态。编译执行如下脚本:
$cd /app/complied/spark-1.1.0-mvn
$export MAVEN_OPTS="-Xmx2g -XX:MaxPermSize=512M -XX:ReservedCodeCacheSize=512m"
$mvn -Pyarn -Phadoop-2.2 -Pspark-ganglia-lgpl -Pkinesis-asl -Phive -DskipTests clean package
整个编译过程编译了约 24 个任务,整个过程耗时 1 小时 45 分钟。
在 Spark 源码根目录下有一个生成部署包的脚本 make-distribution.sh ,可以通过执行如下命令进行打包 ./make-distribution.sh [--name] [--tgz] [--with-tachyon] <maven build options>
l --name NAME 和 --tgz 结合可以生成 spark-$VERSION-bin-$NAME.tgz 的部署包,不加此参数时 NAME 为 hadoop 的版本号
l --tgz 在根目录下生成 spark-$VERSION-bin.tgz ,不加此参数时不生成 tgz 文件,只生成 /dist 目录
l --with-tachyon 是否支持内存文件系统 Tachyon ,不加此参数时不支持 tachyon
例子:
1. 生成支持 yarn 、 hadoop2.2.0 、 hive 的部署包:
./make-distribution.sh --tgz --name 2.2.0 -Pyarn -Phadoop-2.2 -Phive
2. 生成支持 yarn 、 hadoop2.2.0 、 hive 、 ganglia 的部署包:
./make-distribution.sh --tgz --name 2.2.0 -Pyarn -Phadoop-2.2 -Pspark-ganglia-lgpl -P hive
使用如下命令生成 Spark 部署包,由于该脚本默认在 JDK1.6 进行,在开始时会进行询问是否继续,只要选择 Y 即可
$cd /app/complied/spark-1.1.0-mvn/
$./make-distribution.sh --tgz --name 2.2.0 -Pyarn -Phadoop-2.2 -Pspark-ganglia-lgpl -P hive
生成 Spark 部署包编译了约 24 个任务,用时大概 1 小时 38 分钟。
生成在部署包位于根目录下,文件名类似于 spark-1.1.0-bin-2.2.0.tgz 。
1. 我们使用上一步骤编译好的 spark-1.1.0-bin-2.2.0.tgz 文件作为安装包(也可以从网上下载 native 文件夹或者打包好的 64 位 hadoop 安装包),使用 " Spark 编译与部署(上) " 中 1. 3.1 介绍的工具上传到 /home/hadoop/upload 目录下
2. 在主节点上解压缩
$cd /home/hadoop/upload/
$tar -xzf spark-1.1.0-bin-2.2.0.tgz
3. 把 spark 改名并移动到 /app/hadoop 目录下
$mv spark-1.1.0-bin-2.2.0 /app/hadoop/spark-1.1.0
$ll /app/hadoop
1. 打开配置文件 /etc/profile
$sudo vi /etc/profile
2. 定义 SPARK_HOME 并把 spark 路径加入到 PATH 参数中
SPARK_HOME=/app/hadoop/spark-1.1.0
PATH=$PATH:$SPARK_HOME/bin:$SPARK_HOME/sbin
1. 打开配置文件 conf/slaves
$cd /app/hadoop/spark-1.1.0/conf
$sudo vi slaves
2. 加入 slave 配置节点
hadoop1
hadoop2
hadoop3
1. 打开配置文件 conf/spark-env.sh
$cd /app/hadoop/spark-1.1.0/conf
$cp spark-env.sh.template spark-env.sh
$sudo vi spark-env.sh
2. 加入 Spark 环境配置内容,设置 hadoop1 为 Master 节点
export SPARK_MASTER_IP=hadoop1
export SPARK_MASTER_PORT=7077
export SPARK_WORKER_CORES=1
export SPARK_WORKER_INSTANCES=1
export SPARK_WORKER_MEMORY=512M
1. 进入 hadoop1 机器 /app/hadoop 目录,使用如下命令把 spark 文件夹复制到 hadoop2 和 hadoop3 机器
$cd /app/hadoop
$scp -r spark-1.1.0 hadoop@hadoop2:/app/hadoop/
$scp -r spark-1.1.0 hadoop@hadoop3:/app/hadoop/
2. 在从节点查看是否复制成功
$cd /app/hadoop/spark-1.1.0/sbin
$./start-all.sh
此时在 hadoop1 上面运行的进程有: Worker 和 Master
此时在 hadoop2 和 hadoop3 上面运行的进程有只有 Worker
通过 netstat -nlt 命令查看 hadoop1 节点网络情况
在浏览器中输入 http://hadoop1:8080 (需要注意的是要在网络设置中把 hadoop* 除外,否则会到外网 DNS 解析,出现无法访问的情况) 既可以进入 Spark 集群状态页面
进入 hadoop1 节点,进入 spark 的 bin 目录,使用 spark-shell 连接集群
$cd /app/hadoop/spark-1.1.0/bin
$spark-shell --master spark://hadoop1:7077 --executor-memory 500m
在命令中只指定了内存大小并没有指定核数,所以该客户端将占用该集群所有核并在每个节点分配 500M 内存
这里我们测试一下在 Hadoop 中大家都知道的 WordCout 程序,在 MapReduce 实现 WordCout 需要 Map 、 Reduce 和 Job 三个部分,而在 Spark 中甚至一行就能够搞定。下面就看一下是如何实现的:
$cd /app/hadoop/hadoop-2.2.0/sbin
$./start-dfs.sh
通过 jps 观察启动情况,在 hadoop1 上面运行的进程有: NameNode 、 SecondaryNameNode 和 DataNode
hadoop2 和 hadoop3 上面运行的进程有: NameNode 和 DataNode
把 hadoop 配置文件 core-site.xml 文件作为测试文件上传到 HDFS 中
$hadoop fs -mkdir -p /user/hadoop/testdata
$hadoop fs -put /app/hadoop/hadoop-2.2.0/etc/hadoop/core-site.xml /user/hadoop/testdata
$cd /app/hadoop/spark-1.1.0/sbin
$./start-all.sh
在 spark 客户端(这里在 hadoop1 节点 ) ,使用 spark-shell 连接集群
$cd /app/hadoop/spark-1.1.0/bin
$./spark-shell --master spark://hadoop1:7077 --executor-memory 512m --driver-memory 500m
下面就是 WordCount 的执行脚本,该脚本是 scala 编写,以下为一行实现:
scala>sc.textFile("hdfs://hadoop1:9000/user/hadoop/testdata/core-site.xml").flatMap(_.split(" ")).map(x=>(x,1)).reduceByKey(_+_).map(x=>(x._2,x._1)).sortByKey(false).map(x=>(x._2,x._1)).take(10)
为了更好看到实现过程,下面将逐行进行实现:
scala>val rdd=sc.textFile("hdfs://hadoop1:9000/user/hadoop/testdata/core-site.xml")
scala>rdd.cache()
scala>val wordcount=rdd.flatMap(_.split(" ")).map(x=>(x,1)).reduceByKey(_+_)
scala>wordcount.take(10)
scala>val wordsort=wordcount.map(x=>(x._2,x._1)).sortByKey(false).map(x=>(x._2,x._1))
scala>wordsort.take(10)
词频统计结果如下:
Array[(String, Int)] = Array(("",100), (the,7), (</property>,6), (<property>,6), (under,3), (in,3), (License,3), (this,2), (-->,2), (file.,2))
通过 http://hadoop1:8080 查看 Spark 运行情况,可以看到 Spark 为 3 个节点,每个节点各为 1 个内核 /512M 内存,客户端分配 3 个核,每个核有 512M 内存。
通过点击客户端运行任务 ID ,可以看到该任务在 hadoop2 和 hadoop3 节点上运行,在 hadoop1 上并没有运行,主要是由于 hadoop1 为 NameNode 和 Spark 客户端造成内存占用过大造成
从 Spark1.0.0 开始, Spark 提供了一个易用的应用程序部署工具 bin/spark-submit ,可以完成 Spark 应用程序在 local 、 Standalone 、 YARN 、 Mesos 上的快捷部署。该工具语法及参数说明如下:
Usage: spark-submit [options] <app jar | python file> [app options]
Options:
--master MASTER_URL spark://host:port, mesos://host:port, yarn, or local.
--deploy-mode DEPLOY_MODE driver 运行之处, client 运行在本机, cluster 运行在集群
--class CLASS_NAME 应用程序包的要运行的 class
--name NAME 应用程序名称
--jars JARS 用逗号隔开的 driver 本地 jar 包列表以及 executor 类路径
--py-files PY_FILES 用逗号隔开的放置在 Python 应用程序
PYTHONPATH 上的 .zip, .egg, .py 文件列表
--files FILES 用逗号隔开的要放置在每个 executor 工作目录的文件列表
--properties-file FILE 设置应用程序属性的文件放置位置,默认是 conf/spark-defaults.conf
--driver-memory MEM driver 内存大小,默认 512M
--driver-java-options driver 的 java 选项
--driver-library-path driver 的库路径 Extra library path entries to pass to the driver
--driver-class-path driver 的类路径,用 --jars 添加的 jar 包会自动包含在类路径里
--executor-memory MEM executor 内存大小,默认 1G
Spark standalone with cluster deploy mode only:
--driver-cores NUM driver 使用内核数,默认为 1
--supervise 如果设置了该参数, driver 失败是会重启
Spark standalone and Mesos only:
--total-executor-cores NUM executor 使用的总核数
YARN-only:
--executor-cores NUM 每个 executor 使用的内核数,默认为 1
--queue QUEUE_NAME 提交应用程序给哪个 YARN 的队列,默认是 default 队列
--num-executors NUM 启动的 executor 数量,默认是 2 个
--archives ARCHIVES 被每个 executor 提取到工作目录的档案列表,用逗号隔开
该脚本为 Spark 自带例子,在该例子中个计算了圆周率π的值,以下为执行脚本:
$cd /app/hadoop/spark-1.1.0/bin
$./spark-submit --master spark://hadoop1:7077 --class org.apache.spark.examples.SparkPi --executor-memory 512m ../lib/spark-examples-1.1.0-hadoop2.2.0.jar 200
参数说明(详细可以参考上面的参数说明):
l --master Master 所在地址,可以有 Mesos 、 Spark 、 YARN 和 Local 四种,在这里为 Spark Standalone 集群,地址为 spark://hadoop1:7077
l --class 应用程序调用的类名,这里为 org.apache.spark.examples.SparkPi
l --executor-memory 每个 executor 所分配的内存大小,这里为 512M
l 执行 jar 包 这里是 ../lib/spark-examples-1.1.0-hadoop2.2.0.jar
l 分片数目 这里数目为 200
通过观察 Spark 集群有 3 个 Worker 节点和正在运行的 1 个应用程序,每个 Worker 节点为 1 内核 /512M 内存。由于没有指定应用程序所占内核数目,则该应用程序占用该集群所有 3 个内核,并且每个节点分配 512M 内存。
根据每个节点负载情况,每个节点运行 executor 并不相同,其中 hadoop1 的 executor 数目为 0 。而 hadoop3 执行 executor 数为 10 个,其中 5 个 EXITED 状态, 5 个 KILLED 状态。
该脚本为 Spark 自带例子,在该例子中个计算了圆周率π的值,区别脚本 1 这里指定了每个 executor 内核数据,以下为执行脚本:
$cd /app/hadoop/spark-1.1.0/bin
$./spark-submit --master spark://hadoop1:7077 --class org.apache.spark.examples.SparkPi --executor-memory 512m --total-executor-cores 2 ../lib/spark-examples-1.1.0-hadoop2.2.0.jar 200
参数说明(详细可以参考上面的参数说明):
l --master Master 所在地址,可以有 Mesos 、 Spark 、 YARN 和 Local 四种,在这里为 Spark Standalone 集群,地址为 spark://hadoop1:7077
l --class 应用程序调用的类名,这里为 org.apache.spark.examples.SparkPi
l --executor-memory 每个 executor 所分配的内存大小,这里为 512M
l --total-executor-cores 2 每个 executor 分配的内核数
l 执行 jar 包 这里是 ../lib/spark-examples-1.1.0-hadoop2.2.0.jar
l 分片数目 这里数目为 200
通过观察 Spark 集群有 3 个 Worker 节点和正在运行的 1 个应用程序,每个 Worker 节点为 1 内核 /512M 内存。由于指定应用程序所占内核数目为 2 ,则该应用程序使用该集群所有 2 个内核。