![4444fe365ceed70d30ded47dda5a331b.png](https://i-blog.csdnimg.cn/blog_migrate/1d2822fbf45e59d736ba1a54aa0631c6.jpeg)
一、Spark算子分类?
二、Spark RDD的宽窄依赖
三、Spark中Stage pipeline 计算模式
四、Spark计算模式的代码验证
Spark 分布式计算框架之Stage
一、Spark算子分类
![1b1977adb91a9de40e9e34a6b5c4ee0c.png](https://i-blog.csdnimg.cn/blog_migrate/9867f3871dacd231393f89ae157c74d9.png)
Spark中的算子分为三类:
1. Transformation 类算子
Transformation类算子又叫转换算子,在Spark中负责数据的转换,但是由于Spark中迭代器模式处理数据,具备懒执行的特点。
Transformation类算子举例:flatMap,map,reduceByKey等。
2. Action类算子
Action类算子又叫行动算子,是用来触发Transformation类算子执行的。在Spark中每当有一个Action算子就会有一个job。
Action算子举例:count,foreach。
1. 持久化类算子
持久化算子在Spark中是对RDD进行持久化的,算子举例:cache,persist,checkpoint。
一、Spark RDD的宽窄依赖
![fb1707eb92dbf9d0d511c9ea1f174cd9.png](https://i-blog.csdnimg.cn/blog_migrate/a45357601b61aa79668c4d5f59b01a61.png)
RDD:Resilient Distributed Dataset,弹性分布式数据集。由于Spark在处理数据过程中,数据有可能是在同一个节点上进行处理,也有可能在不同的节点上进行处理,形成了RDD至今的宽窄依赖,RDD的宽依赖是会产生shuffle的。
RDD之间是有宽窄依赖之分的,如上图所示,RDD1、RDD2、RDD3三个RDD之间进行转换时,数据都是由上一个RDD的某个分区全部流转到下个RDD的一个分区中,这种关系就是RDD的窄依赖。
当RDD3生成RDD4时,RDD3中某个分区中的数据被分往了RDD4中多个分区中,这种依赖关系就是宽依赖,这个过程在节点之间是由数据传输的,也就是shuffle过程。也就是说宽依赖处理数据时一定伴随shuffle的产生。
以上RDD设置这种宽窄依赖的处理方式是为了更好的并行化处理数据同时更好的适应各种数据处理场景。
![65d44207f70a9223e82f4b0fc4f1f5a4.png](https://i-blog.csdnimg.cn/blog_migrate/57fe287f08b7c99624c8a7093d128e79.png)
上图是在MR中shuffle的过程,在Spark中,shuffle的过程与MR中shuffle的过程类似。由于shuffle原因所以有些RDD之间的依赖是shuffle依赖。
如果父RDD与子RDD之间的依赖关系是一对一 ,这就是窄依赖。
如果父RDD与子RDD之间的依赖关系是多对一,这就是宽依赖。
![57b6e0da07d71264f011fdbfa75c7788.png](https://i-blog.csdnimg.cn/blog_migrate/2ff2d44c8d1b47b40470e7eaffd49b69.png)
三、Spark中stage pipeline计算模式
![db739701661f7209347b1fb74f5c73ea.png](https://i-blog.csdnimg.cn/blog_migrate/758b8ec2828a51965ce6288192fcc5c5.png)
以上解释了RDD的宽窄依赖关系,在Spark底层处理数据时,会生成对应的stage阶段,当RDD依赖关系有一个宽衣关系时,就会有一个Stage阶段的产生,因为当前这个Stage中的数据是没有数据合并的过程,只是单纯的对数据并行的处理过程。当宽依赖关系产生下一个RDD时,会生成下一个Stage,下一个Stage中处理数据的来源就是上一个Stage处理数据的结果,Stage2再次数据数据时,会将相同类型的数据从不同的节点上经过shuffle聚合在一起,然后继续处理,这样达到大数据处理数据的聚合统计过程。
![5032805622fa1513e28d8bfa02ab09d5.png](https://i-blog.csdnimg.cn/blog_migrate/cca5b31e46ef07723d323e3f668774cd.jpeg)
那么在每个Stage处理数据时,每个Stage是有并行度的,这里的并行度由组成Stage的RDD的block个数决定,一般是Stage中最后一个RDD的partition个数决定。这样,每个并行度的task都会被发往对应的数据源头节点上处理数据,以达到并行处理数据的目的。以上Spark这种处理数据的模型就叫做pipeline管道计算模式,其实形成Stage这种pipeline管道计算模式的归根结底的原因是底层迭代器这种处理数据的方式,处理数据量大的场景时Spark不需要更多的内存,只需要保证到当前task需要的内存即可。
四、Spark计算模式的代码验证
创建maven项目,在pom.xml文件中修改pom.xml内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.bjsxt.MyFirstSpark</groupId>
<artifactId>SparkProject</artifactId>
<version>1.0-SNAPSHOT</version>
<name>SparkProject</name>
<!-- 配置以下可以解决 在jdk1.8环境下打包时报错 “-source 1.5 中不支持 lambda 表达式” -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!-- Spark-core -->
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_2.11</artifactId>
<version>2.3.1</version>
</dependency>
<!-- Scala 包-->
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.11.7</version>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-compiler</artifactId>
<version>2.11.7</version>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-reflect</artifactId>
<version>2.11.7</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 在maven项目中既有java又有scala代码时配置 maven-scala-plugin 插件打包时可以将两类代码一起打包 -->
<plugin>
<groupId>org.scala-tools</groupId>
<artifactId>maven-scala-plugin</artifactId>
<version>2.15.2</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Scala代码验证pipeline计算模式:
1. val conf = new SparkConf()
2. conf.setMaster("local")
3. conf.setAppName("pipelineTest")
4. val sc =new SparkContext(conf)
5.
6. val lines = sc.textFile("./data/words")
7. val words = lines.flatMap(line=>{
8. println(s"**** flatMap ****")
9. line.split(" ")
10. })
11. val result = words.map(word=>{
12. println(s"**** map ****")
13. new Tuple2(word,1)
14. })
15. //foreach就是触发算子,触发迭代器的执行
16. result.foreach(println)