在阿里云ECS的Ubuntu中安装Spark

大数据技术原理与应用

返回《在阿里云中搭建大数据实验环境》首页
提示:本教程是一个系列文章,请务必按照本教程首页中给出的各个步骤列表,按照先后顺序一步步进行操作,本博客假设你已经顺利完成了之前的操作步骤。
现在介绍如何在阿里云ECS的Ubuntu系统中安装Spark,本教程采用的版本是Spark2.1.0。Spark部署模式主要有四种:Local模式(单机模式)、Standalone模式(使用Spark自带的简单集群管理器)、YARN模式(使用YARN作为集群管理器)和Mesos模式(使用Mesos作为集群管理器)。这里介绍Local模式(单机模式)的 Spark安装。

安装Spark

可以到Spark官网下载Spark2.1.0安装包,或者,直接到笔者提供的百度云盘下载。笔者已经把Spark安装包保存到了百度云盘中,可以点击这里直接从百度云盘下载文件spark-2.1.0-bin-without-hadoop.tgz。下载成功以后,可以在本地电脑,打开FTP软件,使用linziyu用户名登录到阿里云ECS的Ubuntu系统,把spark-2.1.0-bin-without-hadoop.tgz通过FTP软件上传到“/home/linziyu/Downloads”目录下。
然后,在本地电脑通过VNC Viewer连接远程的阿里云ECS实例中的Ubuntu系统(使用用户名linziyu),打开一个命令行终端,执行如下命令进行Spark的安装:

cd ~
sudo tar -zxvf /home/linziyu/Downloads/spark-2.1.0-bin-without-hadoop.tgz -C /usr/local
cd /usr/local
sudo mv ./spark-2.1.0 ./spark
sudo chown -R linziyu:linziyu ./spark

然后,修改Spark配置文件:

cd /usr/local/spark
cp ./conf/spark-env.sh.template ./conf/spark-env.sh

编辑spark-env.sh文件(vim ./conf/spark-env.sh),在第一行添加以下配置信息:

export SPARK_DIST_CLASSPATH=$(/usr/local/hadoop/bin/hadoop classpath)

有了上面的配置信息以后,Spark就可以把数据存储到Hadoop分布式文件系统HDFS中,也可以从HDFS中读取数据。如果没有配置上面信息,Spark就只能读写本地数据,无法读写HDFS数据。
配置完成后就可以直接使用,不需要像Hadoop运行启动命令。
通过运行Spark自带的示例,验证Spark是否安装成功。

cd /usr/local/spark
./bin/run-example SparkPi

执行时会输出非常多的运行信息,输出结果不容易找到,可以通过 grep 命令进行过滤(命令中的 2>&1 可以将所有的信息都输出到 stdout 中,否则由于输出日志的性质,还是会输出到屏幕中):

cd /usr/local/spark
./bin/run-example SparkPi 2>&1 | grep "Pi is"

这里涉及到Linux Shell中管道的知识,详情可以参考Linux Shell中的管道命令
过滤后的运行结果可以得到π 的 5 位小数近似值,效果如下:

linziyu@iZbp11gznj7n38xkztu64dZ:/usr/local/spark$ ./bin/run-example SparkPi 2>&1 | grep "Pi is"
Pi is roughly 3.1414157070785356

启动进入spark-shell交互式执行环境

在Ubuntu终端里面,执行如下命令启动进入spark-shell交互式执行环境:

cd /usr/local/spark
./bin/spark-shell

然后,会在屏幕上显示如下信息:

linziyu@iZbp11gznj7n38xkztu64dZ:/usr/local/spark$ ./bin/spark-shell
Setting default log level to "WARN".
To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).
18/04/08 09:48:49 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
Spark context Web UI available at http://192.168.1.106:4040
Spark context available as 'sc' (master = local[*], app id = local-1523262130155).
Spark session available as 'spark'.
Welcome to
      ____              __
     / __/__  ___ _____/ /__
    _\ \/ _ \/ _ `/ __/  '_/
   /___/ .__/\_,_/_/ /_/\_\   version 2.1.0
      /_/

Using Scala version 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_162)
Type in expressions to have them evaluated.
Type :help for more information.

scala> 

这样就进入了交互式执行环境,可以在里面输入Scala代码并执行:

scala> 3+5
res0: Int = 8

然后,使用如下命令退出spark-shell交互式环境:

scala> :quit

测试Spark是否可以正常访问Ubuntu系统中的本地文件

在Ubuntu系统中打开一个终端(当前登录用户是linziyu),进行如命令行提示符状态,然后,在Ubuntu系统的本地文件系统目录中,进入到用户linziyu的主目录,使用vim编辑器新建一个word.txt文本文件,具体命令如下:

cd /home/linziyu
vim word.txt

在word.txt文件中随意输入几行英文单词(比如第一行输入:I love Spark 第2行输入:I love Hadoop 第3行输入:Spark is good),保存文件并退出vim编辑器。
然后,再新建一个终端,新建的终端会在新的窗口中,有多个终端窗口存在时,可以在不同终端窗口之间进行切换,切换到你要操作的终端窗口。
新建一个终端以后,在这个新的终端里面,执行如下命令启动进入spark-shell交互式执行环境:

cd /usr/local/spark
./bin/spark-shell

启动以后就进入了“scala>”命令提示符状态,下面可以在Scala交互式环境中执行如下命令测试是否可以正常访问word.txt:

scala> val line=sc.textFile("file:///home/linziyu/word.txt")
line: org.apache.spark.rdd.RDD[String] = file:///home/linziyu/word.txt MapPartitionsRDD[5] at textFile at <console>:24
scala> println(line.count())
3

如果能够运行得到上述结果,说明Spark可以正常访问Ubuntu系统中的本地文件word.txt。

测试Spark是否能够正常访问Hadoop中的HDFS

由于我们经常需要让Spark去访问Hadoop中的HDFS,因此,需要测试一下Spark是否可以正常访问HDFS。
首先,请在阿里云ECS的Ubuntu系统中打开一个终端,执行如下命令启动Hadoop中的HDFS:

cd /usr/local/hadoop
./sbin/start-dfs.sh

然后,执行jps查看是否成功启动:

linziyu@iZbp11gznj6m26xkztu64dZ:/usr/local/hadoop$ jps
21923 Jps
21592 DataNode
21417 NameNode
21806 SecondaryNameNode

如果看到了至少上述4个进程,则表示HDFS启动成功。
下面开始在命令行终端中使用HDFS Shell操作命令,对HDFS进行相关操作,如果不熟悉HDFS Shell命令,请点击这里阅读HDFS Shell命令使用方法
然后,使用如下命令,为当前登录Ubuntu系统的用户linziyu,在HDFS中创建linziyu的对应“主目录”,也就是“hdfs://192.168.0.106:9000/user/linziyu”:

cd /usr/local/hadoop
./bin/hdfs dfs -mkdir -p /user/linziyu

然后,把上面已经建好的Ubuntu系统中的本地文件/home/linziyu/word.txt上传到HDFS中,命令如下:

cd /usr/local/hadoop
./bin/hdfs dfs -put /home/linziyu/word.txt /user/linziyu

上传成功以后,可以使用如下命令查看一下HDFS中的word.txt的内容:

cd /usr/local/hadoop
./bin/hdfs dfs -cat /user/linziyu/word.txt

这时屏幕上就会显示出word.txt中的各行单词。

然后,在Ubuntu的终端中启动进入spark-shell交互式执行环境,去测试Spark读取HDFS数据是否成功,首先使用阿里云ECS实例的私有IP地址去测试:

scala> val line=sc.textFile("hdfs://192.168.1.106:9000/user/linziyu/word.txt")
line: org.apache.spark.rdd.RDD[String] = hdfs://172.16.206.36:9000/user/linziyu/word.txt MapPartitionsRDD[5] at textFile at <console>:24

scala> println(line.count())
java.lang.IllegalArgumentException: java.net.URISyntaxException: Relative path in absolute URI: 192.168.1.106:9000
//会出现错误信息,此处省略更多错误信息

注意,上面的192.168.1.106这个IP地址是阿里云ECS实例的私网IP地址(不是公网IP地址),你可以在你的阿里云ECS网页管理控制台中查询到你的ECS实例的私网IP地址,你的ECS实例的私网IP地址应该不会和192.168.1.106相同,请替换成你的私网IP地址。
可以看到,上述访问方式是不行的,会报错。

下面我们使用另外一种方式去测试:

scala> val line=sc.textFile("hdfs:///127.0.0.1:9000/user/linziyu/word.txt")
line: org.apache.spark.rdd.RDD[String] = hdfs:///127.0.0.1:9000/user/linziyu/word.txt MapPartitionsRDD[11] at textFile at <console>:24

scala> println(line.count())
java.lang.IllegalArgumentException: java.net.URISyntaxException: Relative path in absolute URI: 127.0.0.1:9000
//会出现错误信息,此处省略更多错误信息

可以看到,上述访问方式是不行的,会报错。

下面我们使用另外一种方式去测试:

scala> val line=sc.textFile("hdfs:///localhost:9000/user/linziyu/word.txt")
line: org.apache.spark.rdd.RDD[String] = hdfs:///localhost:9000/user/linziyu/word.txt MapPartitionsRDD[13] at textFile at <console>:24

scala> println(line.count())
java.lang.IllegalArgumentException: java.net.URISyntaxException: Relative path in absolute URI: localhost:9000
//会出现错误信息,此处省略更多错误信息

可以看到,上述访问方式是不行的,会报错。

下面我们使用阿里云ECS实例的公网IP地址去测试:

scala> val line=sc.textFile("hdfs:///48.94.171.104:9000/user/linziyu/word.txt")
line: org.apache.spark.rdd.RDD[String] = hdfs:///48.94.171.104:9000/user/linziyu/word.txt MapPartitionsRDD[15] at textFile at <console>:24

scala> println(line.count())
java.lang.IllegalArgumentException: java.net.URISyntaxException: Relative path in absolute URI: 48.94.171.104:9000
//会出现错误信息,此处省略更多错误信息

可以看到,上述访问方式是不行的,会报错。

下面我们使用另外一种方式去测试:

scala> val line=sc.textFile("/user/linziyu/word.txt")
line: org.apache.spark.rdd.RDD[String] = /user/linziyu/word.txt MapPartitionsRDD[7] at textFile at <console>:24

scala> println(line.count())
3 
//运行成功

可以看出,这种方式可以成功运行。
下面我们再使用另外一种方式去测试:

scala> val line=sc.textFile("word.txt")
line: org.apache.spark.rdd.RDD[String] = word.txt MapPartitionsRDD[9] at textFile at <console>:24

scala> println(line.count())
3
//运行成功

可以看出,这种方式可以成功运行。
所以,总结一下,在spark-shell交互式环境中,要访问HDFS中的文件时,可以直接使用sc.textFile(“/user/linziyu/word.txt”)和sc.textFile(“word.txt”)这两种路径格式。但是,需要注意的是,这两种路径格式,在IntelliJ IDEA中,又会出错,后面有篇博客会专门介绍如何使用IntelliJ IDEA工具调试Spark应用程序,在那篇博客中,会解决这个问题。

实际上,如果通过修改/etc/hosts这个文件,我们也可以让下面这种采用阿里云ECS实例的私网IP地址的测试也能够成功。

scala> val line=sc.textFile("hdfs://192.168.1.106:9000/user/linziyu/word.txt")

具体方法如下:
使用用户名linziyu登录ECS中的Ubuntu系统,打开一个终端,执行如下命令修改hosts文件内容:

cd ~
sudo vim /etc/hosts

/etc/hosts这个文件的原来内容如下:

192.168.1.106 iZbp11gznj7n38xkztu64dZ
127.0.0.1       localhost

# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

修改后,请把里面的最后三行注释掉,使用#可以注释掉一行内容,修改后如下:

192.168.1.106 iZbp11gznj7n38xkztu64dZ
127.0.0.1       localhost

# The following lines are desirable for IPv6 capable hosts
#::1     localhost ip6-localhost ip6-loopback
#ff02::1 ip6-allnodes
#ff02::2 ip6-allrouters

修改后保存文件并退出vim编辑器。
这时,执行下面语句就可以成功了:

scala>  val line=sc.textFile("hdfs://192.168.1.106:9000/user/linziyu/word.txt")
line: org.apache.spark.rdd.RDD[String] = hdfs://192.168.1.106:9000/user/linziyu/word.txt MapPartitionsRDD[29] at textFile at <console>:24

scala> println(line.count())
3