大数据之路系列之spark(08)
SPARK
- 大数据之路系列之spark(08)
- 一、spark是什么?
- 二、spark包含什么?
- 三、测试spark on yarn
- 1.spark测试执行
- 四、Spark的工作原理
- 2.RDD的特点
- 五、Spark的架构
- 六、WordCount程序
- 1.创建maven项目
- 2.添加Scala
- 3.xml 依赖
- 4.Scala代码
- 5.Java代码
- 6.任务提交
- 1.idea
- 2.使用spark-submit
- 1.打包配置
- 2.spark-core作用于设置成provided
- 3.删除master名称配置
- 4.打包后执行jar
- 3.使用spark-shell
- 八、transformation和action算子
- 1.创建RDD
- (1).集合方式
- (2).本地方式和hdfs方式创建RDD
- 2.Transformation和Action
- 3.常用Transformation介绍
- 4.常用action介绍
- 九、RDD持久化
- 十、共享变量
提示:以下是本篇文章正文内容,下面案例可供参考
一、spark是什么?
spark是大规模数据处理的计算引擎,基于内存的计算引擎。
二、spark包含什么?
底层是Hadoop的hdfs和yarn
Spark core指的是Spark的离线批处理
Spark Streaming指的是Spark的实时流计算
SparkSQL指的是Spark中的SQL计算
Spark Mlib指的是Spark中的机器学习库,这里面集成了很多机器学习算法
最后这个Spark GraphX是指图计算
三、测试spark on yarn
yarn地址:http://node01:8088/cluster/apps
1.spark测试执行
不需要启动spark进程
--class 指定需要指定的入口类,表示计算π值
--master指定集群的地址
接着指定需要提交的任务jar包,最后的一个参数是计算π值这个任务自身需要的
接着指定需要提交的任务jar包,最后的一个参数是计算π值这个任务自身需要的
bin/spark-submit --class org.apache.spark.examples.SparkPi --master yarn --deploy-mode cluster examples/jars/spark-examples_2.11-2.4.3.jar 2
四、Spark的工作原理
工作原理:首先通过spark客户端提交任务到spark集群,然后spark任务在执行的过程中会读取数据源(hdfs等),将数据加载到内存中,转化为RDD,RDD会落在不同的分区,对RDD调用高阶函数进行并行处理。
2.RDD的特点
RDD是弹性分布式数据集
分布式:RDD是被分区的,被并行执行
容错性:自动从节点失败中恢复过来
五、Spark的架构
- 首先我们在spark的客户端机器上通过driver进程执行我们的Spark代码
- 当我们通过spark-submit脚本提交Spark任务的时候Driver进程就启动了。
- Driver进程启动之后,会做一些初始化的操作,会找到集群master进程,对Spark应用程序进行注册
- 当Master收到Spark程序的注册申请之后,会发送请求给Worker,进行资源的调度和分配
- Worker收到Master的请求之后,会为Spark应用启动Executor进程会启动一个或者多个Executor,具体启动多少个,会根据你的配置来启动
- Executor启动之后,会向Driver进行反注册,这样Driver就知道哪些Executor在为它服务了
- Driver会根据我们对RDD定义的操作,提交一堆的task去Executor上执行
- task里面执行的其实就是具体的map、flatMap这些操作。
六、WordCount程序
1.创建maven项目
2.添加Scala
1.下载Scala的插件
2.设置全局的依赖
3.当前模块添加依赖
3.xml 依赖
2.11代表Scala的版本
org.apache.spark
spark-core_2.11
2.4.3
4.Scala代码
package com.scala
import org.apache.spark.{SparkConf, SparkContext}
/**
* 需求:单词计数
* Created by xuwei
*/
object WordCountScala {
def main(args: Array[String]): Unit = {
//第一步:创建SparkContext
val conf = new SparkConf()
conf.setAppName("WordCountScala")//设置任务名称
.setMaster("local")//local表示在本地执行
val sc = new SparkContext(conf)
//第二步:加载数据
val linesRDD = sc.textFile("D:\\hello.txt")
//第三步:对数据进行切割,把一行数据切分成一个一个的单词
val wordsRDD = linesRDD.flatMap(_.split(" "))
//第四步:迭代words,将每个word转化为(word,1)这种形式
val pairRDD = wordsRDD.map((_,1))
//第五步:根据key(其实就是word)进行分组聚合统计
val wordCountRDD = pairRDD.reduceByKey(_ + _)
//第六步:将结果打印到控制台
wordCountRDD.foreach(wordCount=>println(wordCount._1+"--"+wordCount._2))
//第七步:停止SparkContext
sc.stop()
}
}
5.Java代码
public static void main(String[] args) {
SparkConf sparkConf = new SparkConf().setAppName("wordCountJava").setMaster("local");
JavaSparkContext sc = new JavaSparkContext(sparkConf);
JavaRDD<String> testRDD = sc.textFile("C:\\project\\db_spark\\src\\main\\resources\\TODO.txt");
JavaRDD<String> flatMapRDD = testRDD.flatMap(x -> Arrays.stream(StringUtils.split(x, " ")).iterator());
JavaPairRDD<String, Integer> mapTPair = flatMapRDD.mapToPair(x -> new Tuple2<String, Integer>(x, 1));
JavaPairRDD<String, Integer> reduceByKeyRDD = mapTPair.reduceByKey((x, y) -> x + y);
reduceByKeyRDD.foreach(x-> System.out.println(x._1+":"+x._2));
sc.stop();
}
6.任务提交
1.idea
本地测试,执行运行
2.使用spark-submit
1.打包配置
<build>
<plugins>
<!-- java编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<!-- scala编译插件 -->
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>3.1.6</version>
<configuration>
<scalaCompatVersion>2.11</scalaCompatVersion>
<scalaVersion>2.11.12</scalaVersion>
</configuration>
<executions>
<execution>
<id>compile-scala</id>
<phase>compile</phase>
<goals>
<goal>add-source</goal>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>test-compile-scala</id>
<phase>test-compile</phase>
<goals>
<goal>add-source</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- 打包插件 -->
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass></mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
2.spark-core作用于设置成provided
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_2.12</artifactId>
<version>2.4.3</version>
<scope>provided</scope>
</dependency>
3.删除master名称配置
local表示的本地测试执行
//.setMaster(“local”)//local表示在本地执行
//第二步:加载数据
var path = “D:\hello.txt”
if(args.length==1){
path = args(0)
}
4.打包后执行jar
提示:这里的包目录不需要文件的后缀名
--deploy-mode client 和--deploy-mode cluster 区别下一章有说明
[root@bigdata04 sparkjars]# vi wordCountJob.sh
spark-submit \
--class com.imooc.scala.WordCountScala \
--master yarn \
--deploy-mode cluster \
--executor-memory 1G \
--num-executors 1 \
db_spark-1.0-SNAPSHOT-jar-with-dependencies.jar \
hdfs://bigdata01:9000/test/hello.txt
3.使用spark-shell
park-shell --master yarn --deploy-mode client
八、transformation和action算子
1.创建RDD
(1).集合方式
val arr=Array(1,2,3,4)
val arrRDD: RDD[Int] = sc.parallelize(arr)
(2).本地方式和hdfs方式创建RDD
Spark默认会为HDFS文件的每一个Block创建一个partition,也可以通过textFile()的第二个参数手动设置分区数量,只能比Block数量多,不能比Block数量少,比Block数量少的话你的设置是不生效的:
JavaRDD<String> testRDD = sc.textFile(filePath,2);
2.Transformation和Action
transformation:转换,lazy特性,transformation不会触发spark任务的执行,直到遇到action操作以后才会执行,避免过多中间结果产生。
action:执行
3.常用Transformation介绍
算子 介绍
map 将RDD中的每个元素进行处理,一进一出
filter 对RDD中每个元素进行判断,返回true则保留
flatMap 与map类似,但是每个元素都可以返回一个或多个新元素
groupByKey 根据key进行分组,每个key对应一个Iterable<value>
reduceByKey 对每个相同key对应的value进行reduce操作
sortByKey 对每个相同key对应的value进行排序操作(全局排序)
join 对两个包含<key,value>对的RDD进行join操作
distinct 对RDD中的元素进行全局去重
4.常用action介绍
算子 介绍
reduce 将RDD中的所有元素进行聚合操作
collect 将RDD中所有元素获取到本地客户端(Driver)
count 获取RDD中元素总数
take(n) 获取RDD中前n个元素
saveAsTextFile 将RDD中元素保存到文件中,对每个元素调用toString
countByKey 对每个key对应的值进行count计数
foreach 遍历RDD中的每个元素
九、RDD持久化
在一个RDD需要反复执行多次的时候,就可以持久化RDD避免重复计算。
代码
rdd.cache(); //简化版本等同于 rdd.persist(MEMORY_ONLY());
rdd.persist(StorageLevel.MEMORY_ONLY()); //使用内存
rdd.persist(StorageLevel.MEMORY_ONLY_SER(h)); //序列化
rdd.persist(StorageLevel.MEMORY_ONLY_SER_2()); //多备份一份
选择策略
1.优先使用MEMORY_ONLY,纯内存速度最快,而且没有序列化不需要消耗CPU进行反序列化操作,缺点就是比较耗内存
2.MEMORY_ONLY_SER,将数据进行序列化存储,纯内存操作还是非常快,只是在使用的时候需要消耗CPU进行反序列化
3.如果需要进行数据的快速恢复,就选择后缀带_2的策略,进行数据备份,这样失败的时候就不需要重新计算了。
十、共享变量
##1.broadcast val 广播变量
普通的变量,每个task都会拷贝一份,广播变量是每个节点拷贝一份。
广播变量是定值,不能修改
作用就是减少内存消耗
//定义广播变量
Broadcast<Integer> broadcast = sc.broadcast(2);
//使用广播变量
JavaRDD<Integer> map = dataRDD.map(x -> x * broadcast.value());
##2.accumulator
LongAccumulator longAccumulator = sc.sc().longAccumulator("2");
dataRDD.foreach(x->longAccumulator.add(x));
System.out.println(longAccumulator.value());