摘录自:https://datawhalechina.github.io/juicy-bigdata/#/ch08-Spark
MapReduce每一个步骤发生在内存中,但产生的中间值(溢写文件)都会写入在磁盘里,下一步操作时又会将这个中间值merge
到内存中,如此循环直到最终完成计算。
而对于Spark,每个步骤也是发生在内存之中,但产生的中间值会直接进入下一个步骤,直到所有的步骤完成之后才会将最终结果保存进磁盘。所以在使用Spark做数据分析时,较少进行很多次相对没有意义的读写,节省大量的时间。当计算步骤很多时,Spark的优势就体现出来了。
Hadoop和Spark两者都是大数据框架,但是各自存在的目的不同。Hadoop实质上是一个分布式数据基础设施,它将巨大的数据集分派到一个集群中的多个节点进行存储,并具有计算处理的功能。Spark则不会进行分布式数据的存储,是计算分布式数据的工具,可以部分看做是MapReduce的竞品(准确的说是SparkCore)
弹性数据集(Resilient Distributed Datasets)
一、分区
二、可并行计算
RDD的每一个分区都会被一个计算任务(Task)处理,每个分区有计算函数(具体执行的计算算子),计算函数以分片为基本单位进行并行计算,RDD的分区数决定着并行计算的数量。
三、依赖关系
依赖关系列表会告诉Spark如何从必要的输入来构建RDD。当遇到错误需要重算时,Spark可以根据这些依赖关系重新执行操作,以此来重建RDD。依赖关系赋予了RDD的容错机制。
四、Key-Value数据的RDD分区器
Spark目前支持Hash
分区(默认分区)和Range
分区,用户也可以自定义分区。
值得注意的是,其本身只针对于key-value的形式(key-value形式的RDD才有Partitioner属性),Partitioner会从0到numPartitions-1
区间内映射每一个key
到partition ID
上。
五、每个分区都有一个优先位置列表
函数的返回值还是RDD
用于计算的map(func)
函数、用于过滤的filter(func)
函数、用于合并数据集的union(otherDataset)
函数、用于根据key
聚合的reduceByKey(func, [numPartitions])
函数、用于连接数据集的join(otherDataset, [numPartitions])
函数、用于分组的groupByKey([numPartitions])
函数等。
这种函数不返回RDD
Spark的DAGScheduler
遇到Shuffle
时,会生成一个计算阶段,在遇到action
函数时,会生成一个作业(Job)。RDD里的每个数据分片,Spark都会创建一个计算任务进行处理,所以,一个计算阶段会包含多个计算任务(Task)。
MapReduce中,一个应用一次只运行一个map
和一个reduce
,而Spark可以根据应用的复杂程度,将过程分割成更多的计算阶段(stage),这些计算阶段组成一个有向无环图(DAG),Spark任务调度器根据DAG的依赖关系执行计算阶段(stage)。
DAG是有向无环图,即是说不同阶段的依赖关系是有向的,计算过程只能沿着依赖关系方向执行,被依赖的阶段执行完成之前,依赖的阶段不能开始执行,同时,这个依赖关系不能是环形依赖,否则就造成死循环。
Spark中计算阶段划分的依据是Shuffle,而不是操作函数的类型,并不是所有的函数都有Shuffle
过程。比如Spark计算阶段示例图中,RDD B和RDD F进行join后,得到RDD G。RDD B不需要Shuffle,因为RDD B在上一个阶段中,已经进行了数据分区,分区数和分区key不变,就不需要进行Shuffle
。而RDD F的分区数不同,就需要进行Shuffle
。Spark把不需要Shuffle的依赖,称为窄依赖。需要Shuffle的依赖,称为宽依赖。Shuffle
是Spark最重要的一个环节,只有通过Shuffle
,相关数据才能互相计算,从而构建起复杂的应用逻辑。