1、掌握spark相关概念
2、掌握搭建一个spark集群
3、掌握编写简单的spark应用程序
Apache Spark™ is a unified analytics engine for large-scale data processing.
apache的spark是一个针对于大规模数据处理的统一分析引擎
spark是基于内存计算的大数据处理框架,由于基于内存计算,处理数据非常快。这里仅仅只涉及到数据的计算,并没有涉及到数据的存储,后期就需要对接各种不同的外部数据源,比如处理HDFS上的数据。
1、速度快
spark比mapreduce在内存中快100倍,比mapreduce在磁盘中快10倍
spark比mapreduce快的主要2个原因
(1)mapreduce的任务每一个job它的输出结果只能够保存在磁盘,后续有其他的job需要依赖于前面job的输出结果,这个时候需要进行大量的磁盘io操作。 spark的任务每一个job它的输出结果可以保存在内存中,后续有其他的job需要依赖于前面job的输出结果,这个时候就可以直接在内存中获取得到,大大减少磁盘io操作,最后提升了性能。
例如: select name,age from (select * from user where age >30 and age <40)
(2) mapreduce的任务它是以进程的方式运行在yarn集群中,比如一个job有100个MapTask,这个时候就需要开启100个进程去处理这个100个task。spark的任务它是以线程的方式运行在进程中,比如一个job有100个MapTask,这个时候就可以极端一点:只启动一个进程,在这个进程运行100个线程。这里开启一个进程和开启一个线程代价是不一样,开启一个进程需要的时间和资源比线程要大大增加。spark中可以减少大量的时间资源调度,提升性能。
2、易用性
3、通用性
4、兼容性
spark任务就是一个计算程序,哪里可以给当前这个程序提供对应的计算资源,我们就可以把程序提交到哪里去。
yarn
standalone
mesos
1、下载spark对应的安装包
2、规划安装目录
3、上传安装包到服务器中
4、解压安装包到指定的规划目录中
tar -zxvf spark-2.1.3-bin-hadoop2.7.tgz -C /export/servers
5、重命名解压目录
mv spark-2.1.3-bin-hadoop2.7 spark
6、修改配置文件
进入到spark安装目录有一个conf文件夹
vim spark-env.sh
(mv spark-env.sh.template spark-env.sh)
#配置java环境变量 ,集合自己的java_home路径
export JAVA_HOME=/export/servers/jdk
#指定master的地址
export SPARK_MASTER_HOST=node1
#指定master的端口
export SPARK_MASTER_PORT=7077
vim slaves
(mv slaves.template slaves
)
在slaves配置文件的最后将localhost删除 , 然后添加node-2 , node-3
#指定哪些节点是worker
node-2
node-3
7、配置spark环境变量
vim /etc/profile
export SPARK_HOME=/export/servers/spark
export PATH=$PATH:$SPARK_HOME/bin:$SPARK_HOME/sbin
8、分发spark安装目录和spark环境变量
scp -r spark node-2:/export/servers
scp -r spark node-3:/export/servers
scp /etc/profile node2:/etc
scp /etc/profile node3:/etc
9、让所有节点的spark环境变量生效
启动spark集群
./start-all.sh
停止spark集群
需要在主节点(master所有在机器)中进入到spark安装目录下有一个sbin文件夹
./stop-all.sh
node-1:8080
1、搭建zk集群
2、修改配置文件
vim spark-env.sh
#注释掉手动指定master地址配置
#export SPARK_MASTER_HOST=node-1
#引入zk构建spark高可用集群
export SPARK_DAEMON_JAVA_OPTS="-Dspark.deploy.recoveryMode=ZOOKEEPER -Dspark.deploy.zookeeper.url=node-1:2181,n
ode-2:2181,node-3:2181 -Dspark.deploy.zookeeper.dir=/spark"
然后拷贝到其他机器上
scp spark-env.sh node-2:$PWD
scp spark-env.sh node-3:$PWD
PWD表示统计目录
3、启动zk集群
4、启动spark集群
可以在任意一台机器启动脚本(前提条件:实现任意2台机器之间的ssh免密登录)
start-all.sh
可以在其他机器单独启动master
start-master.sh
spark高可用集群master恢复
引入zk之后,可以启动很多个master,其中有一个master被选举成活着的master,它去提供服务,其他多个naster处于standBy状态(备用),启动好之后,它会把整个spark集群的元数据信息写入到zk配置好的节点中(/spark).
如果活着的master挂掉了,首先zk会感知到,接下来它会在所有处于standBy中的master进行选举生成一个新的活着的master,活着的master它会读取到zk中保存spark集群元数据信息的节点,最后进行恢复,恢复到上一次挂掉的master状态,整个恢复过程需要1-2分钟。
当前活着的master挂掉之后有什么影响?
(1)对于正在运行的任务有没有影响?
没有任何影响。原因:对于正在运行的任务,就说明已经获取得到资源,这个时候就不需要master,可以继续运行,不受任何影响。
(2)对于要提交的任务有没有影响?
有影响,由于没有这样一个活着的master提供资源的分配,这个任务就获取不到资源,既然获取不到资源,任务就无法运行。
1、Driver端
2、Application
3、ClusterManager
4、Master
5、Worker
6、Executor
7、task
1、普通模式提交任务(就是我们事先知道了哪个Master是活着的Master)
bin/spark-submit \
--class org.apache.spark.examples.SparkPi \
--master spark://node2:7077 \
--executor-memory 1G \
--total-executor-cores 2 \
examples/jars/spark-examples_2.11-2.1.3.jar \
10
2、高可用模式下提交任务(整个集群有很多个Master,事先并不知道哪个master是活着的master)
bin/spark-submit \
--class org.apache.spark.examples.SparkPi \
--master spark://node1:7077,node3:7077,node2:7077 \
--executor-memory 1G \
--total-executor-cores 2 \
examples/jars/spark-examples_2.11-2.1.3.jar \
10
实际企业中,master肯定是很多个,这个时候任务的提交需要找活着的master申请资源,由于master特别多,我们无法快速判断哪个master是活着的master,即使判断出了哪个master是活着的master,它也有可能下一秒就挂掉了,这个时候就可以在提交任务的时候指定 --master spark://node-1:7077,node-3:7077,node-2:7077 把所有的master地址都进行罗列。
后期整个程序会依次轮训整个master列表,最后找到活着的master,然后向这个活着的master申请资源。
资源分配根据自己电脑性能来
–master local[N]
提交脚本
spark-shell --master local[2] 它会产生一个SparkSubmit进程
sc.textFile("file:///root/words.txt").flatMap(x=>x.split(" ")).map(x=>(x,1)).reduceByKey((x,y)=>x+y).collect
sc.textFile("file:///root/words.txt").flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).collect
spark整合hdfs
vim spark-env.sh
export HADOOP_CONF_DIR=/export/servers/hadoop/etc/hadoop
提交脚本
spark-shell --master local[2]
sc.textFile("/words.txt").flatMap(x=>x.split(" ")).map(x=>(x,1)).reduceByKey((x,y)=>x+y).collect
sc.textFile("hdfs://node-1:9000/words.txt").flatMap(x=>x.split(" ")).map(x=>(x,1)).reduceByKey((x,y)=>x+y).collect
把任务提交到集群中运行
提交脚本
spark-shell --master spark://node-2:7077
sc.textFile("/words.txt").flatMap(x=>x.split(" ")).map(x=>(x,1)).reduceByKey((x,y)=>x+y).collect
sc.textFile("/words.txt").flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).saveAsTextFile("/out")
1、引入pom依赖
<properties>
<scala.version>2.11.8scala.version>
<hadoop.version>2.7.4hadoop.version>
<spark.version>2.1.3spark.version>
properties>
<dependencies>
<dependency>
<groupId>org.scala-langgroupId>
<artifactId>scala-libraryartifactId>
<version>${scala.version}version>
dependency>
<dependency>
<groupId>org.apache.sparkgroupId>
<artifactId>spark-core_2.11artifactId>
<version>${spark.version}version>
dependency>
dependencies>
<build>
<sourceDirectory>src/main/scalasourceDirectory>
<testSourceDirectory>src/test/scalatestSourceDirectory>
<plugins>
<plugin>
<groupId>net.alchim31.mavengroupId>
<artifactId>scala-maven-pluginartifactId>
<version>3.2.2version>
<executions>
<execution>
<goals>
<goal>compilegoal>
<goal>testCompilegoal>
goals>
<configuration>
<args>
<arg>-dependencyfilearg>
<arg>${project.build.directory}/.scala_dependenciesarg>
args>
configuration>
execution>
executions>
plugin>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-shade-pluginartifactId>
<version>2.4.3version>
<executions>
<execution>
<phase>packagephase>
<goals>
<goal>shadegoal>
goals>
<configuration>
<filters>
<filter>
<artifact>*:*artifact>
<excludes>
<exclude>META-INF/*.SFexclude>
<exclude>META-INF/*.DSAexclude>
<exclude>META-INF/*.RSAexclude>
excludes>
filter>
filters>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>mainClass>
transformer>
transformers>
configuration>
execution>
executions>
plugin>
plugins>
build>
代码开发
package cn.itcast.spark
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
//todo:利用scala语言开发spark的wordcount程序(本地运行)
object WordCount {
def main(args: Array[String]): Unit = {
//1、创建SparkConf对象 设置applicationName和master地址 local[2]表示本地采用2个线程
val sparkConf: SparkConf = new SparkConf().setAppName("WordCount").setMaster("local[2]")
//2、创建SparkContext对象,它是所有spark程序执行入口,它内部会构建DAGScheduler和TaskScheduler
val sc = new SparkContext(sparkConf)
//设置日志输出级别
sc.setLogLevel("warn")
//3、读取文件数据
val data: RDD[String] = sc.textFile("E:\\words.txt")
//4、切分每一行,获取所有的单词
val words: RDD[String] = data.flatMap(x=>x.split(" "))
//5、每个单词计为1
val wordAndOne: RDD[(String, Int)] = words.map(x =>(x,1))
//6、相同单词出现的1累加
val result: RDD[(String, Int)] = wordAndOne.reduceByKey((x:Int,y:Int)=>x+y)
//按照单词出现的次数降序排列 默认第二个参数是true,在这里表示升序,改为false就是降序
val sortedRDD: RDD[(String, Int)] = result.sortBy(x => x._2,false)
//7、收集数据打印
val finalResult: Array[(String, Int)] = sortedRDD.collect
finalResult.foreach(x=>println(x))
//8、关闭sc
sc.stop()
}
}
1、代码开发
package cn.itcast.spark
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.rdd.RDD
//todo:利用scala语言开发spark的wordcount程序(集群运行)
object WordCount_Online {
def main(args: Array[String]): Unit = {
//1、创建SparkConf对象 设置applicationName
val sparkConf: SparkConf = new SparkConf().setAppName("WordCount_Online")
//2、创建SparkContext对象,它是所有spark程序执行入口,它内部会构建DAGScheduler和TaskScheduler
val sc = new SparkContext(sparkConf)
//设置日志输出级别
sc.setLogLevel("warn")
//3、读取文件数据
val data: RDD[String] = sc.textFile(args(0))
//4、切分每一行,获取所有的单词
val words: RDD[String] = data.flatMap(x=>x.split(" "))
//5、每个单词计为1
val wordAndOne: RDD[(String, Int)] = words.map(x =>(x,1))
//6、相同单词出现的1累加
val result: RDD[(String, Int)] = wordAndOne.reduceByKey((x:Int,y:Int)=>x+y)
//7、把最后的结果数据保存到hdfs上
result.saveAsTextFile(args(1))
//8、关闭sc
sc.stop()
}
}
2、打成jar包集群运行
spark-submit --master spark://node-1:7077,node-2:7077,node-3:7077 --class cn.itcast.spark.WordCount_Online --executor-memory 512M --total-executor-cores 1 original-spark_class14-1.0-SNAPSHOT.jar /words.txt /out_spark
1、代码开发
package cn.itcast.spark;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.FlatMapFunction;
import org.apache.spark.api.java.function.Function2;
import org.apache.spark.api.java.function.PairFunction;
import scala.Tuple2;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
//todo:利用java语言开发spark的wordcount程序(本地运行)
public class WordCount_Java {
public static void main(String[] args) {
//1、创建SparkConf
SparkConf sparkConf = new SparkConf().setAppName("WordCount_Java").setMaster("local[2]");
//2、创建JavaSparkContext
JavaSparkContext jsc = new JavaSparkContext(sparkConf);
//3、读取文件数据
JavaRDD data = jsc.textFile("E:\\words.txt");
//4、切分每一行,获取所有的单词
JavaRDD words = data.flatMap(new FlatMapFunction() {
public Iterator call(String line) throws Exception {
String[] lines = line.split(" ");
return Arrays.asList(lines).iterator();
}
});
//5、每个单词计为1
JavaPairRDD wordAndOne = words.mapToPair(new PairFunction() {
public Tuple2 call(String word) throws Exception {
return new Tuple2(word, 1);
}
});
//6、相同单词出现的1累加
JavaPairRDD result = wordAndOne.reduceByKey(new Function2() {
public Integer call(Integer v1, Integer v2) throws Exception {
return v1 + v2;
}
});
//按照单词出现的次数降序排列 (单词,次数)----->(次数,单词).sortByKey----->(单词,次数)
JavaPairRDD reverseRDD = result.mapToPair(new PairFunction, Integer, String>() {
public Tuple2 call(Tuple2 t) throws Exception {
return new Tuple2(t._2, t._1);
}
});
JavaPairRDD sortedRDD = reverseRDD.sortByKey(false).mapToPair(new PairFunction, String, Integer>() {
public Tuple2 call(Tuple2 t) throws Exception {
return new Tuple2(t._2, t._1);
}
});
//7、收集打印
List> finalResult = sortedRDD.collect();
for (Tuple2 t : finalResult) {
System.out.println("单词:"+t._1+" 次数:"+t._2);
}
//8、关闭jsc
jsc.stop();
}
}