一、Spark的概述:
spark是什么
spark是基于内存的计算框架,计算速度非常快。如果想要对接外部的数据,比如HDFS读取数据,需要事先搭建一个 hadoop 集群。
为什么要学习spark
* 1、spark运行速度比mapreduce快很多
* spark的job中间处理结果可以保存在内存中。mapreduce每次任务的结果输出都会保存在磁盘
* mapreduce中,最终任务是进程中方式去计算任务。比如有100个map任务,1个reduce任务。至少会使用到101个进程。
* spark中,最终任务是以线程的方式去计算任务,比如说有100个task,它就会在进程中运行100个线程。大大节省进程(资源)的开销,速度得到提升。
二、Spark的特点
三、Spark集群的搭建
四、基于zookeeper的Spark的高可用搭建
* 1、搭建一个zookeeper集群
* 2、修改spark配置文件
* vi spark-env.sh
* 注释掉 export SPARK_MASTER_HOST=node1
* 引入zk配置
```
export SPARK_DAEMON_JAVA_OPTS="-Dspark.deploy.recoveryMode=ZOOKEEPER -Dspark.deploy.zookeeper.url=hdp-node-01:2181,node02:2181,node03:2181 -Dspark.deploy.zookeeper.dir=/spark"
```
* 3、启动spark HA
* 1、启动zk
* 2、可以在任意一台服务器上执行 start-all.sh
* 会在当前机器上产生一个master进程
* 3、在其他节点单独启动master进程(注意:需要实现当前节点到其他worker节点的ssh 免登陆)
* start-master.sh
五、Spark角色介绍
* 1、Driver
* 就是运行客户端程序的main方法,会创建sparkContext
* 2、Application
* 就是一个spark应用程序,包含driver以及运行任务所需要的所有资源
* 3、master
* 在spark standalone模式下,用于对资源进行分配
* 4、Cluster manager
* 为当前程序运行提供外部的资源
* standalone
* 由master提供资源分配
* yarn
* 由resourcemanager提供资源分配
* mesos
* 也是一个资源调度框架
* 5、worker
* 就是运行任务的节点
* 6、executor
* 是运行在worker节点上的进程,负责任务的计算
* 7、task
* spark程序最终是以task线程的方式运行在executor进程中
六、检测是够安装成功
计算圆周率
* 普通模式提交
```
bin/spark-submit \
--class org.apache.spark.examples.SparkPi \
--master spark://node01:7077 \
--executor-memory 1G \
--total-executor-cores 2 \
examples/jars/spark-examples_2.11-2.0.2.jar \
10
```
* 高可用模式提交
```
bin/spark-submit \
--class org.apache.spark.examples.SparkPi \
--master spark://node01:7077,node02:7077,node03:7077 \
--executor-memory 1G \
--total-executor-cores 2 \
examples/jars/spark-examples_2.11-2.0.2.jar \
10
```
七、spark-shell
spark-shell是Spark自带的交互式Shell程序,方便用户进行交互式编程,用户可以在该命令行下用scala编写spark程序
* 1、通过spark-shell --master local[2] 读取本地数据文件做一个wordcount
* --master local[2]
* 表示本地运行程序,跟集群没有任何关系
* local[N]这里的N,它是正整数,表示本地采用N个线程去运行
* --master local[*]
* local[*]: *表示使用当前机器上所有可用的资源去运行程序
* 2、通过spark-shell --master local[2]读取HDFS上数据文件做一个wordcount
* 需要指定文件的路径为HDFS上文件路径
* sc.textFile("hdfs://node1:9000/words.txt").flatMap(_.split(" ")).map((_,1)).reduceByKey(\_+\_).collect
* spark整合HDFS
* vi spark-env.sh
* 添加
* export HADOOP_CONF_DIR=/export/servers/hadoop/etc/hadoop
* 3、通过spark-shell --master spark://node1:7077 读取HDFS上数据文件做一个wordcount
* spark-shell --master spark://node1:7077
* sc.textFile("/words.txt").flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).collect
八使用IDEA编写WordCount案例
* 需要导入依赖
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_2.11</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>2.7.4</version>
</dependency>
* 利用scala语言编写spark的wordcount程序(本地运行)
package cn.itcast.wordcount
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.rdd.RDD
//todo:需求:利用scala语言编写spark的wordcount程序
object WordCount {
def main(args: Array[String]): Unit = {
//1、创建sparkConf对象 设置appName和master地址 local[2] 表示本地采用2个线程去运行
val sparkConf: SparkConf = new SparkConf().setAppName("WordCount").setMaster("local[2]")
//2、创建sparkContext对象
val sc = new SparkContext(sparkConf)
//设置日志输出级别
sc.setLogLevel("WARN")
//3、通过sparkContext对象加载数据文件
val data: RDD[String] = sc.textFile("D:\\words.txt")
//4、切分每一行
val words: RDD[String] = data.flatMap(_.split(" "))
//5、每个单词计为1
val wordAndOne: RDD[(String, Int)] = words.map((_,1))
//6、相同单词出现的次数累加
val result: RDD[(String, Int)] = wordAndOne.reduceByKey(_+_)
//7、收集打印
println(result.sortBy(_._2,false).collect().toBuffer)
//保存结果数据
result.saveAsTextFile("d:\\out123")
//8、关闭sc
sc.stop()
}
}
* 利用scala语言编写spark的wordcount程序(集群运行)
package cn.itcast.wordcount
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.rdd.RDD
//todo:利用scala编写spark wordcount程序打成jar提交到集群中运行
object WordCount_Online {
def main(args: Array[String]): Unit = {
//1、创建sparkConf对象 设置appName
val sparkConf: SparkConf = new SparkConf().setAppName("WordCount")
//2、创建sparkContext对象
val sc = new SparkContext(sparkConf)
//设置日志输出级别
sc.setLogLevel("WARN")
//3、通过sparkContext对象加载数据文件
val data: RDD[String] = sc.textFile(args(0))
//4、切分每一行
val words: RDD[String] = data.flatMap(_.split(" "))
//5、每个单词计为1
val wordAndOne: RDD[(String, Int)] = words.map((_,1))
//6、相同单词出现的次数累加
val result: RDD[(String, Int)] = wordAndOne.reduceByKey(_+_)
//7、保存结果数据到HDFS上
result.saveAsTextFile(args(1))
//8、关闭sc
sc.stop()
}
}
提交任务脚本:
spark-submit --master spark://node1:7077 --class cn.itcast.wordcount.WordCount_Online --executor-memory 1g --total-executor-cores 2 original-spark-class03-2.0.jar /words.txt /out2018
* 利用java语言编写spark的wordcount程序(本地运行)
package cn.itcast.wordcount;
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,设置appName和master地址
SparkConf sparkConf = new SparkConf().setAppName("WordCount_Java").setMaster("local[2]");
//2、构建javaSparkContext对象
JavaSparkContext jsc = new JavaSparkContext(sparkConf);
//3、读取数据文件
JavaRDD<String> dataJavaRDD = jsc.textFile("d:\\words.txt");
//4、切分每一行
JavaRDD<String> wordsJavaRDD = dataJavaRDD.flatMap(new FlatMapFunction<String, String>() {
public Iterator<String> call(String line) throws Exception {
String[] words = line.split(" ");
return Arrays.asList(words).iterator();
}
});
//5、每个单词记为1
JavaPairRDD<String, Integer> wordAndOneJavaPairRDD = wordsJavaRDD.mapToPair(new PairFunction<String, String, Integer>() {
public Tuple2<String, Integer> call(String word) throws Exception {
return new Tuple2<String, Integer>(word, 1);
}
});
//6、相同单词出现的次数累加
JavaPairRDD<String, Integer> resultJavaPairRDD = wordAndOneJavaPairRDD.reduceByKey(new Function2<Integer, Integer, Integer>() {
public Integer call(Integer v1, Integer v2) throws Exception {
return v1 + v2;
}
});
//按照单词出现的次数降序排列 resultJavaPairRDD 中(单词,次数) 位置颠倒(次数,单词)然后在使用sortByKey按照次数降序排列,最后位置复原
JavaPairRDD<String, Integer> sortJavaPairRDD = resultJavaPairRDD.mapToPair(new PairFunction<Tuple2<String, Integer>, Integer, String>() {
public Tuple2<Integer, String> call(Tuple2<String, Integer> tuple) throws Exception {
return new Tuple2<Integer, String>(tuple._2, tuple._1);
}
}).sortByKey(false).mapToPair(new PairFunction<Tuple2<Integer, String>, String, Integer>() {
public Tuple2<String, Integer> call(Tuple2<Integer, String> tuple) throws Exception {
return new Tuple2<String, Integer>(tuple._2, tuple._1);
}
});
//7、打印输出
List<Tuple2<String, Integer>> finalResult = sortJavaPairRDD.collect();
for (Tuple2<String, Integer> tuple:finalResult){
System.out.println("单词:"+tuple._1+" 次数:"+tuple._2);
}
//8、关闭jsc
jsc.stop();
}
}