spark
1.1 为什么是spark
- 为分布式数据集的处理提供了一个有效框架,并以高效的方式处理分布式数据集。
- Spark集批处理、实时流处理、交互式查询、机器学习与图计算于一体,避免了多种运算场景下需要部署不同集群带来的资源浪费。
- Spark实现了一种分布式的内存抽象,称为弹性分布式数据集(Resilient Distributed Dataset,RDD )。它支持基于工作集的应用,同时具有数据流模型的特点:自动容错、位置感知性调度和可伸缩(RDD允许用户在执行多个查询时显式地将工作集缓存在内存中,后续的查询能够重用工作集,这极大地提升了查询速度)
2.1 Spark架构
2.2.1Driver Program
用户编写的Spark程序被称为Driver Program。每个Driver程序包含一个代表集群环境的SparkContext对象,程序的执行从Driver程序开始,所有操作之行结束后回到Driver程序中,在Driver程序中结束。如果你使用spark shell,那么当你启动spark shell的时候,系统后台自启一个spark驱动器程序,就是在Spark shell中预加载一个sc的SparkContext对象,如果驱动器程序终止,那么Spark应用也就结束了。
2.3.1 SparkContext对象
每个DriverProgram里都有一个SparkContext对象,职责如下:
- 联系cluster manager(集群管理器),让cluster manager为Worker Node分配CPU、内存、启动执行器等任务。
- 和Executor进程交互,负责任务的调度分配
2.4.1 cluster manager(集群管理器)
对应master进程,集群管理器负责集群的资源调度,如为WorkNode分配CPU、内存等资源。并实时监控Worker的资源使用情况,一个WorkerNode默认情况下分配一个Executor进程
cluster manager只负责资源的管理调度,不负责任务的分配和结果处理
2.5.1 WorkerNode
Worker节点,集群上的计算节点,对应一台物理机器
2.6.1 Worker进程
对应worker节点,用于和Master进程交互,向Master注册和汇报自身节点的资源使用情况,并管理和启动Executor进程。
2.7.1 Executor
负责运行Task计算任务,并将计算结果回传到Driver中
2.8.1 Task
在执行器上执行的最小单元,比如RDD的Transformation操作时对RDD内每个分区的计算都会对应一个Task。
3.1 spark框架核心概念
- RDD:弹性分布式数据集,是spark最核心的数据结构,有分区机制,所以可以分布式进行处理。有容错机制,通过RDD之间的依赖关系来恢复数据
- RDD依赖关系:RDD的依赖关系是通过各种Transformation(变换)来得到的,父RDD和子RDD之间的依赖关系分两种
- 窄依赖:父RDD分区和子RDD分区的关系是一对一,窄依赖不会发生shuffle,执行效率高,spark框架底层会针对多个连续的窄依赖执行流水线优化,从而提高性能
- 宽依赖:父RDD分区和子RDD分区关系是一对多,宽依赖会产生shuffle,会产生磁盘读写,无法优化
- DAG:有向无环图,当一整条RDD的依赖关系形成后,就形成一个DAG,一个DAG最后都至少会触发一个Action操作,触发后开始执行。一个Action对应一个Job任务。
- Stage:一个DAG会根据RDD之间的依赖关系进行Stage划分,流程是:以Action为基准,向前回溯,遇到宽依赖就形成一个Stage,遇到窄依赖就执行流水线优化(将多个连续的窄依赖放到一起执行)
- task:任务。一个分区对应一个task,一个Stage是一组Task的集合
- Transformation:懒执行,不会立即执行
- Action:触发真正的执行
3.2.1 执行步骤
-
构建DAG
提交依赖关系构建的DAG图至DAGScheduler进行解析
-
DAGScheduler进行任务划分
DAGScheduler收到DAG图之后,对该图依据宽窄依赖关系拆分成stage,然后为需要计算的Partition生成TaskSet。
-
TaskScheduler调度任务
TaskScheduler接收来自DAGScheduler发送的TaskSet,并为任务分配资源,然后将其发送到Worker节点上执行
-
Worker执行任务
Worker节点中的Executor收到TaskScheduler发送过来的Task后执行Task
4.1 RDD和DAG
4.2.1 RDD
什么是RDD(弹性分布式数据集):是只读的记录分区的集合,能横跨集群的所有节点进行并行计算,是一种基于工作集的应用抽象,这个数据集的全部或者部分可以缓存在内存中,在多次计算中重用,所谓弹性就是指在内存不够时可以与磁盘进行交换。通过RDD用户可以数据共享,并以一致的方式应对不同的大数据处理场景,提高spark编程的效率和通用性。
特征:分区、函数、依赖(前三个是基本特征)、优先位置、分区策略(后面两个是可选特征)
4.2.2 RDD的依赖关系
RDD之间的父子依赖关系:一个RDD是从哪个RDD转换而来,前者就是子RDD,后者就是父(parent)RDD,根据依赖于parent RDD的分区的不同情况,spark将依赖分为两种,一种是宽依赖,一种是窄依赖。
窄依赖:指每个父RDD分区最多被子RDD的一个分区使用(一对一),窄依赖操作只是将分区的数据根据转换的规则进行转化,并不涉及其他的处理,可以简单的认为只是将数据从一个行使转换到另一个形式所以对于窄依赖,并不会引入昂贵的shuffle,所以执行效率非常高。
如果整个DAG中存在多个连续的窄依赖,则可以将这些连续的窄依赖整合到一起连续执行,中间不执行shuffle从而提高效率,这样的优化方式称为流水线优化。
此外,针对窄依赖,如果子RDD某个分区数据丢失,只需要找到父RDD对应依赖的分区恢复即可,但如果是宽依赖,当分区丢失时,最糟糕的情况是要重算所有父RDD的所有分区。
宽依赖:指多个子RDD的分区会依赖同一个父RDD的分区,子RDD的分区是父RDD的所有分区shuffle的结果。
4.2.3 RDD的容错机制
RDD的容错机制主要是checkpoint(检查点)容错机制。
RDD的缓存能够在第一次计算完成后,将计算结果保存到内存、本地文件系统等地,通过缓存spark避免了RDD上的重复计算,能够极大地提升计算速度,这是RDD的持久化。缓存的方式虽然能够以文件的形式保存到磁盘上,但是磁盘会损坏,文件也会丢失,如果缓存失败了,则需要重新计算,为了避免重新计算,需要更加可靠的检查点机制。
checkpoint将计算完成的数据,放到hdfs上,借助hdfs高容错、高可靠的特性来完成最大化的可靠持久化数据的方式,降低了数据被破坏或者丢失的风险,也减少了数据重新计算时的开销。
checkpoint运行原理:在job结束后,会判断是否需要checkpoint,如果需要就调用doCheckpoint对象为数据创建一个目录,然后启动一个新的job来计算,并将计算结果写入新创建的目录,接着创建一个CheckpointRDD(CheckpointRDD是后面RDD的父RDD,需要的数据从CheckpointRDD来获取)。最后清除原始RDD的所有依赖。
4.3.1 DAG
概念:spark会根据用户提交的计算逻辑中的RDD转换和动作来生成RDD之间的依赖关系,同时这个计算链也就生成了逻辑上的DAG
spark的stage(阶段):spark在执行任务时,首先会根据依赖关系,将DAG划分为不同的阶段。
DAG的处理流程如下:
-
spark在执行Transformation类型的操作时不会立即执行,而是懒执行
-
执行若干步的Transformation类型的操作后,只有遇到Action类型操作才会真正触发执行
-
执行时,从当前Action方法向前回溯,如果遇到窄依赖则流水线优化,遇到宽依赖进行shuffle,无法实现优化。
将遇到窄依赖再遇到宽依赖这一段执行过程组装为一个stage,然后从当前宽依赖开始继续向前找,重复上述步骤,从而将一个DAG分为若干个stage
spark的job和task
RDD转化成为DAG后,会在最后一个RDD上触发一个动作,这个动作会生成一个job,这个job会被划分为一批计算任务(task),这批task会被提交到集群上的计算节点来计算。
spark的task分为两种:
- org.apache.spark.scheduler.ShuffleMapTask
- org.apache.spark.scheduler.ResultTask
简单来说,DAG的最后一个阶段会为每个结果的Partition生成一个ResultTask,其余所有的阶段都会生成ShuffleMapTask。
4.4.1 spark shuffle
什么是spark shuffle:具有某种共同特征的一类数据需要汇聚到一个计算节点上进行计算,中间数据重新打乱然后汇聚到不同节点的流转过程叫shuffle。
shuffle可能会出现的问题:
- 数据量会很大,如单位为TB或PB的数据分散到几百甚至数千、数万台机器上
- 为了将数据汇聚到正确的节点,需要将这些数据放在正确的partition,如果数据的大小大于节点的内存,那么这个过程可能会发生多次硬盘续写
- 为了节省带宽,数据可能需要进行压缩,压缩率和压缩时间需要权衡
- 数据需要通过网络传输,因此数据的序列化和反序列化也变得相对复杂。
shuffle产生文件的原因:Task处理数据时,会对数据进行持久化,对于shuffle来说,如果不持久化这个中间结果,一旦数据丢失,就需要重新计算依赖的所有的RDD,因此需要持久化shuffle产生的中间结果。
shuffle不持久化会出现的问题:
- 可能会造成内存溢出
- 当某分区丢失时,会重新计算所有父分区数据。
5.1 spark SQL
什么是sparkSQL?
spark为结构化数据处理引入了一个称为SparkSql的编程模块。它提供了一个称为DataFrame(数据框)的编程抽象,DF的底层依然是RDD,并且可以充当分布式SQL查询引擎
特点:
- 引入了新的RDD类型的SchemaRDD,可以像传统数据库定义表一样来定义SchemaRDD
- 在应用程序中可以混合使用不同来源的数据,如可以将来自HIVEQL的数据和来自SQL的数据进行join操作
- 内嵌了查询优化框架,在把SQL解析成逻辑执行计划之后,最后变成RDD计算
sparkSQL相对于shark的优化:内存列存储
- 列存储的优势:
- 海量数据查询时,不存在冗余列问题。
- 每一行数据类型都是同质的,这样既可以避免数据在内存中类型的频繁转换,还可以采用更加高效的压缩算法。
- 在空间占用量和读取吞吐率上都占有很大优势
6.1 SparkStreaming
spark Streaming是一种构建在Spark上的实时计算框架,它扩展了spark处理大规模流式数据的能力,以吞吐量和高容错著称
SparkStreaming VS Storm
Spark Streaming的核心抽象是DSTream,里面是RDD,下层是Spark核心DAG调度,所以也决定了Spark Streaming的粒度是小批量的,无法做到精细控制,也是因为数据的可靠性也是以批次为粒度的,但好处也很明显,就是可以实现更大的吞吐量
spark Streaming在开发效率上更占优势。spark Streaming可以使用spark平台上的其他模块,SQL、机器学习等
Storm更擅长细粒度级别的控制,数据可靠性也是以消息为粒度的
核心数据抽象的不同导致了它们在计算模式上的本质区别。Spark Streaming在本质上其实是像MR一样的批处理计算,而且它支持各类数据源,基本可以实现流式计算的功能,Storm设计初衷就是实时计算,而且后期通过更高级别的Trident也实现了小批次处理功能。
6.2.1 Streaming架构及原理
sparkStreaming是一个对实时流处理进行高通量、高容错处理的流式处理系统,可以对多种数据源(如kafka、Flume、Twitter等)进行类似Map、Reduce和join等操作,并将结果保存到外部文件系统、数据库或者实时仪表盘
计算过程:
- Spark Streaming将流式计算分解成一系列短小的批处理作业,也就是把Spark Streaming的输入数据按照batch size分成一段一段的数据DStream
- 将DStream转换成Spark中的RDD
- 将Spark Streaming中对DStream的Transformation操作变为针对Spark中对RDD的Transformation操作
- 将RDD经过操作变成中间结果保存在内存中。
- 根据业务需求对中间结果进行叠加或者存储到外部设备
SparkStreaming的顺序性:对DStream的处理,每个DStream都要按照数据流到达的先后顺序依次进行处理。其本质是转换成RDD的血缘关系,所以SparkStreaming对数据天然具有容错性保证。
为了提高SparkStreaming的工作效率,应该合理的配置时间间隔。
6.2.2 StreamingContext
StreamingContext是Spark Streaming编程的最基本环境对象,就相当于Spark编程中的SparkContext,StreamingContext提供最基本的功能入口,包括从各途径创建最基本的对象DStream(相当于Spark中的RDD)
6.2.3 DStream
DStream是SparkStreaming的核心抽象,相当于Spark中的RDD。DStream表示连续的数据流,要么是从数据源接受到的输入数据流,要么是经过计算产生的新数据流,DStream的内部是一个RDD序列,每个RDD对应一个计算周期,所有应用在DStream上的操作,都会被映射为对DStream内部的RDD的操作。RDD操作将由Spark核心来调度执行,但DStream屏蔽了这些细节,但是可以直接对DStream内部的RDD进行操作。