spark

1.spark集群配置:
修改配置文件conf/spark-env.sh

export JAVA_HOME=/root/apps/jdk1.8.0_201
export SPARK_MASTER_HOST=hdp-0
export SPARK_MASTER_PORT=7077
export SPARK_DAEMON_JAVA_OPTS="-Dspark.deploy.recoveryMode=ZOOKEEPER -Dspark.deploy.zookeeper.url=hdp-1,hdp-2,hdp-3 -Dspark.deploy.zookeeper.dir=/spark"
export SPARK_WORKER_CORES=8
export SPARK_WORKER_MEMORY=6g
export SPARK_LOCAL_IP="192.168.183.132"
export HADOOP_CONF_DIR=$HADOOP_HOME/etc/hadoop

conf/slaves


hdp-1
hdp-2
hdp-3

启动:
1、启动zk

2、启动hdfs start-dfs.sh

3、启动spark sbin/start-all.sh

验证:

http://hdp-0:8080
高可用集群
在worker机器上启动start-master
简介
spark 可以很容易和yarn结合,直接调用HDFS、Hbase上面的数据,和hadoop结合。配置很容易。
spark发展迅猛,框架比hadoop更加灵活实用。减少了延时处理,提高性能效率实用灵活性。也可以与hadoop切实相互结合。
spark核心部分分为RDD。Spark SQL、Spark Streaming、MLlib、GraphX、Spark R等核心组件解决了很多的大数据问题,其完美的框架日受欢迎。其相应的生态环境包括zepplin等可视化方面,正日益壮大。大型公司争相实用spark来代替原有hadoop上相应的功能模块。Spark读写过程不像hadoop溢出写入磁盘,都是基于内存,因此速度很快。另外DAG作业调度系统的宽窄依赖让Spark速度提高。
Spark核心组成

1、RDD

是弹性分布式数据集,完全弹性的,如果数据丢失一部分还可以重建。有自动容错、位置感知调度和可伸缩性,通过数据检查点和记录数据更新金象容错性检查。通过SparkContext.textFile()加载文件变成RDD,然后通过transformation构建新的RDD,通过action将RDD存储到外部系统。

RDD使用延迟加载,也就是懒加载,只有当用到的时候才加载数据。如果加载存储所有的中间过程会浪费空间。因此要延迟加载。一旦spark看到整个变换链,他可以计算仅需的结果数据,如果下面的函数不需要数据那么数据也不会再加载。转换RDD是惰性的,只有在动作中才可以使用它们。

Spark分为driver和executor,driver提交作业,executor是application早worknode上的进程,运行task,driver对应为sparkcontext。Spark的RDD操作有transformation、action。Transformation对RDD进行依赖包装,RDD所对应的依赖都进行DAG的构建并保存,在worknode挂掉之后除了通过备份恢复还可以通过元数据对其保存的依赖再计算一次得到。当作业提交也就是调用runJob时,spark会根据RDD构建DAG图,提交给DAGScheduler,这个DAGScheduler是在SparkContext创建时一同初始化的,他会对作业进行调度处理。当依赖图构建好以后,从action开始进行解析,每一个操作作为一个task,每遇到shuffle就切割成为一个taskSet,并把数据输出到磁盘,如果不是shuffle数据还在内存中存储。就这样再往前推进,直到没有算子,然后运行从前面开始,如果没有action的算子在这里不会执行,直到遇到action为止才开始运行,这就形成了spark的懒加载,taskset提交给TaskSheduler生成TaskSetManager并且提交给Executor运行,运行结束后反馈给DAGScheduler完成一个taskSet,之后再提交下一个,当TaskSet运行失败时就返回DAGScheduler并重新再次创建。一个job里面可能有多个TaskSet,一个application可能包含多个job。

2、Spark Streaming

通过对kafka数据读取,将Stream数据分成小的时间片段(几秒),以类似batch批处理的方式来处理这一部分小数据,每个时间片生成一个RDD,有高效的容错性,对小批量数据可以兼容批量实时数据处理的逻辑算法,用一些历史数据和实时数据联合进行分析,比如分类算法等。也可以对小批量的stream进行mapreduce、join等操作,而保证其实时性。针对数据流时间要求不到毫秒级的工程性问题都可以。

Spark Streaming也有一个StreamingContext,其核心是DStream,是通过以组时间序列上的连续RDD来组成的,包含一个有Time作为key、RDD作为value的结构体,每一个RDD都包含特定时间间隔的数据流,可以通过persist将其持久化。在接受不断的数据流后,在blockGenerator中维护一个队列,将流数据放到队列中,等处理时间间隔到来后将其中的所有数据合并成为一个RDD(这一间隔中的数据)。其作业提交和spark相似,只不过在提交时拿到DStream内部的RDD并产生Job提交,RDD在action触发之后,将job提交给jobManager中的JobQueue,又jobScheduler调度,JobScheduler将job提交到spark的job调度器,然后将job转换成为大量的任务分发给spark集群执行。Job从outputStream中生成的,然后触发反向回溯执行DStreamDAG。在流数据处理的过程中,一般节点失效的处理比离线数据要复杂。Spark streamin在1.3之后可以周期性的将DStream写入HDFS,同时将offset也进行存储,避免写到zk。一旦主节点失效,会通过checkpoint的方式读取之前的数据。当worknode节点失效,如果HDFS或文件作为输入源那Spark会根据依赖关系重新计算数据,如果是基于Kafka、Flume等网络数据源spark会将手机的数据源在集群中的不同节点进行备份,一旦有一个工作节点失效,系统能够根据另一份还存在的数据重新计算,但是如果接受节点失效会丢失一部分数据,同时接受线程会在其他的节点上重新启动并接受数据。

3、Graphx

主要用于图的计算。核心算法有PageRank、SVD奇异矩阵、TriangleConut等。

4、Spark SQL

是Spark新推出的交互式大数据SQL技术。把sql语句翻译成Spark上的RDD操作可以支持Hive、Json等类型的数据。

5、Spark R

通过R语言调用spark,目前不会拥有像Scala或者java那样广泛的API,Spark通过RDD类提供Spark API,并且允许用户使用R交互式方式在集群中运行任务。同时集成了MLlib机器学习类库。

6、MLBase

从上到下包括了MLOptimizer(给使用者)、MLI(给算法使用者)、MLlib(给算法开发者)、Spark。也可以直接使用MLlib。ML Optimizer,一个优化机器学习选择更合适的算法和相关参数的模块,还有MLI进行特征抽取和高级ML编程 抽象算法实现API平台,MLlib分布式机器学习库,可以不断扩充算法。MLRuntime基于spark计算框架,将Spark的分布式计算应用到机器学习领域。MLBase提供了一个简单的声明方法指定机器学习任务,并且动态地选择最优的学习算法。

7、Tachyon

高容错的分布式文件系统。宣称其性能是HDFS的3000多倍。有类似java的接口,也实现了HDFS接口,所以Spark和MR程序不需要任何的修改就可以运行。目前支持HDFS、S3等。

8、Spark算子

大致可以分为三大类算子。

1)Value数据类型的Transformation算子,这种变换并不触发提交作业,针对处理的数据项是Value型的数据。

2)Key-Value数据类型的Transfromation算子,这种变换并不触发提交作业,针对处理的数据项是Key-Value型的数据对。

3)Action算子,这类算子会触发SparkContext提交Job作业。

1)Value数据类型的Transformation算子

1、Map。对原数据进行处理,类似于遍历操作,转换成MappedRDD,原分区不变。

2、flatMap。将原来的RDD中的每一个元素通过函数转换成新的元素,将RDD的每个集合中的元素合并成一个集合。比如一个元素里面多个list,通过这个函数都合并成一个大的list,最经典的就是wordcount中将每一行元素进行分词以后成为,通过flapMap变成一个个的单词,line.flapMap(.split(“ ”)).map((,1))如果通过map就会将一行的单词变成一个list。

3、mapPartitions。对每个分区进行迭代,生成MapPartitionsRDD。

4、glom 函数将每个分区形成一个数组,内部实现是放回的GlommedRDD。

5、Union。是将两个RDD合并成一个。使用这个函数要保证两个RDD元素的数据类型相同,返回的RDD的数据类型和被合并的RDD数据类型相同。

6、cartesian 对两个RDD内所有的元素进行笛卡尔积操作。

7、groupBy:将元素通过函数生成相应的Key,数据就转化为Key-Value,之后将Key相同的元素分为一组。

8、Filter。其功能是对元素进行过滤,对每个元素调用f函数,返回值为true的元素就保留在RDD中。

9、Distinct。对RDD中元素进行去重操作。

10、Subtract。对RDD1中取出RDD1与RDD2交集中的所有元素。

11、Sample。对RDD中的集合内元素进行采样,第一个参数withReplacement是true表示有放回取样,false表示无放回。第二个参数表示比例,第三个参数是随机种子。如data.sample(true, 0.3,new Random().nextInt())。

12、takeSample。和sample用法相同,只不第二个参数换成了个数。返回也不是RDD,而是collect。

13、Cache。将RDD缓存到内存中。相当于persist(MEMORY_ONLY)。可以通过参数设置缓存和运行内存之间的比例,如果数据量大于cache内存则会丢失。

14、Persist。里面参数可以选择DISK_ONLY/MEMORY_ONLY/MEMORY_AND_DISK等,其中的MEMORY_AND_DISK当缓存空间满了后自动溢出到磁盘。

2)Key-Value数据类型的Transfromation算子

1、MapValues。针对KV数据,对数据中的value进行map操作,而不对key进行处理。

2、reduceByKey。针对KV数据将相同key的value聚合到一起。与groupByKey不同,会进行一个类似mapreduce中的combine操作,减少相应的数据IO操作,加快效率。如果想进行一些非叠加操作,我们可以将value组合成字符串或其他格式将相同key的value组合在一起,再通过迭代,组合的数据拆开操作。

3、partitionBy。可以将RDD进行分区,重新生成一个ShuffleRDD,进行一个shuffle操作,对后面进行频繁的shuffle操作可以加快效率。

4、randomSplit。对RDD进行随机切分。如data.randomSplit(new double[]{0.7, 0.3})返回一个RDD的数组。

5、Cogroup。对两个RDD中的KV元素,每个RDD中相同key中的元素分别聚合成一个集合。与reduceByKey不同的是针对两个RDD中相同的key的元素进行合并。

6、Join。相当于inner join。对两个需要连接的RDD进行cogroup,然后对每个key下面的list进行笛卡尔积的操作,输出两两相交的两个集合作为value。 相当于sql中where a.key=b.key。

7、leftOutJoin,rightOutJoin。在数据库中左连接以左表为坐标将表中所有的数据列出来,右面不存在的用null填充。在这里面对join的基础上判断左侧的RDD元素是否是空,如果是空则填充。右连接则相反。

3)Action算子

1、foreach 对RDD中每个元素都应用f函数操作,不返回RDD和Array,而是返回Unit。

2、saveAsTestFile。将数据输出到HDFS的指定目录。

3、saveAsObjectFile。写入HDFS为SequenceFile格式。

4、Collect、collectAsMap。将RDD转换成list或者Map。结果以List或者HashMap的方式输出。

5、reduceByKeyLocally 实现的是先reduce再collectAsMap的功能,先对RDD的整体进行reduce操作,然后再收集所有结果返回为一个HashMap。

6、Count。对RDD的元素进行统计,返回个数。

7、Top(k)。返回最大的k个元素,返回List的形式。

8、Take返回数据的前k个元素。

9、takeOrdered。返回数据的最小的k个元素,并在返回中保持元素的顺序。

10、reduce函数相当于对RDD中的元素进行reduceLeft函数的操作。

11、fold,fold和reduce原理相同,但是与reduce不同,相当于每个reduce时,迭代器取的第一个元素是zeroValue。

12、aggregate,先对每个分区的所有元素进行aggregate操作,再对分区的结果进行fold操作。

9、Tips

1、RDD.repartition(n)可以在最初对RDD进行分区操作,这个操作实际上是一个shuffle,可能比较耗时,但是如果之后的action比较多的话,可以减少下面操作的时间。其中的n值看cpu的个数,一般大于2倍cpu,小于1000。

2、Action不能够太多,每一次的action都会将以上的taskset划分一个job,这样当job增多,而其中task并不释放,会占用更多的内存,使得gc拉低效率。

3、在shuffle前面进行一个过滤,减少shuffle数据,并且过滤掉null值,以及空值。

4、groupBy尽量通过reduceBy替代。reduceBy会在work节点做一次reduce,在整体进行reduce,相当于做了一次hadoop中的combine操作,而combine操作和reduceBy逻辑一致,这个groupBy不能保证。

5、做join的时候,尽量用小RDD去join大RDD,用大RDD去join超大的RDD。

6、避免collect的使用。因为collect如果数据集超大的时候,会通过各个work进行收集,io增多,拉低性能,因此当数据集很大时要save到HDFS。

7、RDD如果后面使用迭代,建议cache,但是一定要估计好数据的大小,避免比cache设定的内存还要大,如果大过内存就会删除之前存储的cache,可能导致计算错误,如果想要完全的存储可以使用persist(MEMORY_AND_DISK),因为cache就是persist(MEMORY_ONLY)。

8、设置spark.cleaner.ttl,定时清除task,因为job的原因可能会缓存很多执行过去的task,所以定时回收可能避免集中gc操作拉低性能。

9、适当pre-partition,通过partitionBy()设定,每次partitionBy会生成一个RDD。

一、RDD的概述

1.1 什么是RDD?
RDD(Resilient Distributed Dataset)叫做弹性分布式数据集,是Spark中最基本的数据抽象,它代表一个不可变、可分区、里面的元素可并行计算的集合。RDD具有数据流模型的特点:自动容错、位置感知性调度和可伸缩性。RDD允许用户在执行多个查询时显式地将工作集缓存在内存中,后续的查询能够重用工作集,这极大地提升了查询速度。

1.2 RDD的属性
(1)一组分片(Partition),即数据集的基本组成单位。对于RDD来说,每个分片都会被一个计算任务处理,并决定并行计算的粒度。用户可以在创建RDD时指定RDD的分片个数,如果没有指定,那么就会采用默认值。默认值就是程序所分配到的CPU Core的数目。

(2)一个计算每个分区的函数。Spark中RDD的计算是以分片为单位的,每个RDD都会实现compute函数以达到这个目的。compute函数会对迭代器进行复合,不需要保存每次计算的结果。

(3)RDD之间的依赖关系。RDD的每次转换都会生成一个新的RDD,所以RDD之间就会形成类似于流水线一样的前后依赖关系。在部分分区数据丢失时,Spark可以通过这个依赖关系重新计算丢失的分区数据,而不是对RDD的所有分区进行重新计算。

(4)一个Partitioner,即RDD的分片函数。当前Spark中实现了两种类型的分片函数,一个是基于哈希的HashPartitioner,另外一个是基于范围的RangePartitioner。只有对于于key-value的RDD,才会有Partitioner,非key-value的RDD的Parititioner的值是None。Partitioner函数不但决定了RDD本身的分片数量,也决定了parent RDD Shuffle输出时的分片数量。

(5)一个列表,存储存取每个Partition的优先位置(preferred location)。对于一个HDFS文件来说,这个列表保存的就是每个Partition所在的块的位置。按照“移动数据不如移动计算”的理念,Spark在进行任务调度的时候,会尽可能地将计算任务分配到其所要处理数据块的存储位置。
二、RDD的创建方式

2.1 通过读取文件生成的
由外部存储系统的数据集创建,包括本地的文件系统,还有所有Hadoop支持的数据集,比如HDFS、Cassandra、HBase等

scala> val file = sc.textFile("/spark/hello.txt")

在这里插入图片描述
2.2 通过并行化的方式创建RDD
由一个已经存在的Scala集合创建。

scala> val array = Array(1,2,3,4,5)
array: Array[Int] = Array(1, 2, 3, 4, 5)
 
scala> val rdd = sc.parallelize(array)
rdd: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[27] at parallelize at <console>:26
 
scala> 
 

在这里插入图片描述

2.3 其他方式
读取数据库等等其他的操作。也可以生成RDD。

RDD可以通过其他的RDD转换而来的。
三、RDD编程API
Spark支持两个类型(算子)操作:Transformation和Action

3.1 Transformation
主要做的是就是将一个已有的RDD生成另外一个RDD。Transformation具有lazy特性(延迟加载)。Transformation算子的代码不会真正被执行。只有当我们的程序里面遇到一个action算子的时候,代码才会真正的被执行。这种设计让Spark更加有效率地运行。

常用的Transformation:
转换

含义

map(func)

返回一个新的RDD,该RDD由每一个输入元素经过func函数转换后组成

filter(func)

返回一个新的RDD,该RDD由经过func函数计算后返回值为true的输入元素组成

flatMap(func)

类似于map,但是每一个输入元素可以被映射为0或多个输出元素(所以func应该返回一个序列,而不是单一元素)

mapPartitions(func)

类似于map,但独立地在RDD的每一个分片上运行,因此在类型为T的RDD上运行时,func的函数类型必须是Iterator[T] => Iterator[U]

mapPartitionsWithIndex(func)

类似于mapPartitions,但func带有一个整数参数表示分片的索引值,因此在类型为T的RDD上运行时,func的函数类型必须是

(Int, Interator[T]) => Iterator[U]

sample(withReplacement, fraction, seed)

根据fraction指定的比例对数据进行采样,可以选择是否使用随机数进行替换,seed用于指定随机数生成器种子

union(otherDataset)

对源RDD和参数RDD求并集后返回一个新的RDD

intersection(otherDataset)

对源RDD和参数RDD求交集后返回一个新的RDD

distinct([numTasks]))

对源RDD进行去重后返回一个新的RDD

groupByKey([numTasks])

在一个(K,V)的RDD上调用,返回一个(K, Iterator[V])的RDD

reduceByKey(func, [numTasks])

在一个(K,V)的RDD上调用,返回一个(K,V)的RDD,使用指定的reduce函数,将相同key的值聚合到一起,与groupByKey类似,reduce任务的个数可以通过第二个可选的参数来设置

aggregateByKey(zeroValue)(seqOp, combOp, [numTasks])

先按分区聚合 再总的聚合 每次要跟初始值交流 例如:aggregateByKey(0)(+,+) 对k/y的RDD进行操作

sortByKey([ascending], [numTasks])

在一个(K,V)的RDD上调用,K必须实现Ordered接口,返回一个按照key进行排序的(K,V)的RDD

sortBy(func,[ascending], [numTasks])

与sortByKey类似,但是更灵活 第一个参数是根据什么排序 第二个是怎么排序 false倒序 第三个排序后分区数 默认与原RDD一样

join(otherDataset, [numTasks])

在类型为(K,V)和(K,W)的RDD上调用,返回一个相同key对应的所有元素对在一起的(K,(V,W))的RDD 相当于内连接(求交集)

cogroup(otherDataset, [numTasks])

在类型为(K,V)和(K,W)的RDD上调用,返回一个(K,(Iterable,Iterable))类型的RDD

cartesian(otherDataset)

两个RDD的笛卡尔积 的成很多个K/V

pipe(command, [envVars])

调用外部程序

coalesce(numPartitions)

重新分区 第一个参数是要分多少区,第二个参数是否shuffle 默认false 少分区变多分区 true 多分区变少分区 false

repartition(numPartitions)

重新分区 必须shuffle 参数是要分多少区 少变多

repartitionAndSortWithinPartitions(partitioner)

重新分区+排序 比先分区再排序效率高 对K/V的RDD进行操作

foldByKey(zeroValue)(seqOp)

该函数用于K/V做折叠,合并处理 ,与aggregate类似 第一个括号的参数应用于每个V值 第二括号函数是聚合例如:+

combineByKey

合并相同的key的值 rdd1.combineByKey(x => x, (a: Int, b: Int) => a + b, (m: Int, n: Int) => m + n)

partitionBy(partitioner)

对RDD进行分区 partitioner是分区器 例如new HashPartition(2

cache

RDD缓存,可以避免重复计算从而减少时间,区别:cache内部调用了persist算子,cache默认就一个缓存级别MEMORY-ONLY ,而persist则可以选择缓存级别

persist

Subtract(rdd)

返回前rdd元素不在后rdd的rdd

leftOuterJoin

leftOuterJoin类似于SQL中的左外关联left outer join,返回结果以前面的RDD为主,关联不上的记录为空。只能用于两个RDD之间的关联,如果要多个RDD关联,多关联几次即可。

rightOuterJoin

rightOuterJoin类似于SQL中的有外关联right outer join,返回结果以参数中的RDD为主,关联不上的记录为空。只能用于两个RDD之间的关联,如果要多个RDD关联,多关联几次即可

subtractByKey

substractByKey和基本转换操作中的subtract类似只不过这里是针对K的,返回在主RDD中出现,并且不在otherRDD中出现的元素

3.2 Action
触发代码的运行,我们一段spark代码里面至少需要有一个action操作。

常用的Action:

动作

含义

reduce(func)

通过func函数聚集RDD中的所有元素,这个功能必须是课交换且可并联的

collect()

在驱动程序中,以数组的形式返回数据集的所有元素

count()

返回RDD的元素个数

first()

返回RDD的第一个元素(类似于take(1))

take(n)

返回一个由数据集的前n个元素组成的数组

takeSample(withReplacement,num, [seed])

返回一个数组,该数组由从数据集中随机采样的num个元素组成,可以选择是否用随机数替换不足的部分,seed用于指定随机数生成器种子

takeOrdered(n, [ordering])

saveAsTextFile(path)

将数据集的元素以textfile的形式保存到HDFS文件系统或者其他支持的文件系统,对于每个元素,Spark将会调用toString方法,将它装换为文件中的文本

saveAsSequenceFile(path)

将数据集中的元素以Hadoop sequencefile的格式保存到指定的目录下,可以使HDFS或者其他Hadoop支持的文件系统。

saveAsObjectFile(path)

countByKey()

针对(K,V)类型的RDD,返回一个(K,Int)的map,表示每一个key对应的元素个数。

foreach(func)

在数据集的每一个元素上,运行函数func进行更新。

aggregate

先对分区进行操作,在总体操作

reduceByKeyLocally

lookup

top

fold

foreachPartition

四、RDD的宽依赖和窄依赖
4.1 RDD依赖关系的本质内幕

由于RDD是粗粒度的操作数据集,每个Transformation操作都会生成一个新的RDD,所以RDD之间就会形成类似流水线的前后依赖关系;RDD和它依赖的父RDD(s)的关系有两种不同的类型,即窄依赖(narrow dependency)和宽依赖(wide dependency)。如图所示显示了RDD之间的依赖关系。

在这里插入图片描述
从图中可知:

窄依赖:是指每个父RDD的一个Partition最多被子RDD的一个Partition所使用,例如map、filter、union等操作都会产生窄依赖;(独生子女)

宽依赖:是指一个父RDD的Partition会被多个子RDD的Partition所使用,例如groupByKey、reduceByKey、sortByKey等操作都会产生宽依赖;(超生)

需要特别说明的是对join操作有两种情况:

(1)图中左半部分join:如果两个RDD在进行join操作时,一个RDD的partition仅仅和另一个RDD中已知个数的Partition进行join,那么这种类型的join操作就是窄依赖,例如图1中左半部分的join操作(join with inputs co-partitioned);

(2)图中右半部分join:其它情况的join操作就是宽依赖,例如图1中右半部分的join操作(join with inputs not co-partitioned),由于是需要父RDD的所有partition进行join的转换,这就涉及到了shuffle,因此这种类型的join操作也是宽依赖。

总结:

在这里我们是从父RDD的partition被使用的个数来定义窄依赖和宽依赖,因此可以用一句话概括下:如果父RDD的一个Partition被子RDD的一个Partition所使用就是窄依赖,否则的话就是宽依赖。因为是确定的partition数量的依赖关系,所以RDD之间的依赖关系就是窄依赖;由此我们可以得出一个推论:即窄依赖不仅包含一对一的窄依赖,还包含一对固定个数的窄依赖。

一对固定个数的窄依赖的理解:即子RDD的partition对父RDD依赖的Partition的数量不会随着RDD数据规模的改变而改变;换句话说,无论是有100T的数据量还是1P的数据量,在窄依赖中,子RDD所依赖的父RDD的partition的个数是确定的,而宽依赖是shuffle级别的,数据量越大,那么子RDD所依赖的父RDD的个数就越多,从而子RDD所依赖的父RDD的partition的个数也会变得越来越多。

4.2 依赖关系下的数据流视图
在这里插入图片描述
在spark中,会根据RDD之间的依赖关系将DAG图(有向无环图)划分为不同的阶段,对于窄依赖,由于partition依赖关系的确定性,partition的转换处理就可以在同一个线程里完成,窄依赖就被spark划分到同一个stage中,而对于宽依赖,只能等父RDD shuffle处理完成后,下一个stage才能开始接下来的计算。

因此spark划分stage的整体思路是:从后往前推,遇到宽依赖就断开,划分为一个stage;遇到窄依赖就将这个RDD加入该stage中。因此在图2中RDD C,RDD D,RDD E,RDDF被构建在一个stage中,RDD A被构建在一个单独的Stage中,而RDD B和RDD G又被构建在同一个stage中。

在spark中,Task的类型分为2种:ShuffleMapTask和ResultTask;

简单来说,DAG的最后一个阶段会为每个结果的partition生成一个ResultTask,即每个Stage里面的Task的数量是由该Stage中最后一个RDD的Partition的数量所决定的!而其余所有阶段都会生成ShuffleMapTask;之所以称之为ShuffleMapTask是因为它需要将自己的计算结果通过shuffle到下一个stage中;也就是说上图中的stage1和stage2相当于mapreduce中的Mapper,而ResultTask所代表的stage3就相当于mapreduce中的reducer。
spark-DAG图
DAG(Directed Acyclic Graph)叫做有向无环图,原始的RDD通过一系列的转换就就形成了DAG,RDD之间的依赖关系形成了DAG图,而根据RDD之间的依赖关系的不同将DAG划分成不同的Stage。

宽窄依赖
窄依赖:父RDD和子RDD partition之间的关系是一对一的。或者父RDD一个partition只对应一个子RDD的partition情况下的父RDD和子RDD partition关系是多对一的。不会有shuffle的产生。父RDD的一个分区去到子RDD的一个分区。

宽依赖:父RDD与子RDD partition之间的关系是一对多。会有shuffle的产生。父RDD的一个分区的数据去到子RDD的不同分区里面。

Stage
Spark任务会根据RDD之间的依赖关系,形成一个DAG有向无环图,DAG会提交给DAGScheduler,DAGScheduler会把DAG划分相互依赖的多个stage,划分stage的依据就是RDD之间的宽窄依赖。

遇到宽依赖就划分stage,每个stage包含一个或多个task任务。然后将这些task以taskSet的形式提交给TaskScheduler运行。stage是由一组并行的task组成。

stage切割规则

切割规则:从后往前,遇到宽依赖就切割stage。

stage类别:ResultStage(reduce), ShuffleMapStage(map)

Shuffle
Shuffle描述着数据从map task输出到reduce task输入的这段过程。shuffle是连接Map和Reduce之间的桥梁,Map的输出要用到Reduce中必须经过shuffle这个环节,shuffle的性能高低直接影响了整个程序的性能和吞吐量。因为在分布式情况下,reduce task需要跨节点去拉取其它节点上的map task结果。这一过程将会产生网络资源消耗和内存,磁盘IO的消耗。通常shuffle分为两部分:Map阶段的数据准备和Reduce阶段的数据拷贝处理。

在之前动手操作了一个wordcount程序,因此可知,Hadoop中MapReduce操作中的Mapper和Reducer在spark中的基本等量算子是map和reduceByKey;不过区别在于:Hadoop中的MapReduce天生就是排序的;而reduceByKey只是根据Key进行reduce,但spark除了这两个算子还有其他的算子;因此从这个意义上来说,Spark比Hadoop的计算算子更为丰富。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值