Spark的基本知识

临近年关将spark近来所学整理一下,若有不足请指正。

一、什么是Spark?

Spark是由加州大学伯克利分校AMP实验室开源的分布式大规模数据处理通用引擎,具有高吞吐,低延时,通用易扩展,高容错等特点。

Spark内部提供了丰富的开发库、提供了多种运行模式,Spark函数式编程语言在Scala中实现。

二、Spark的架构?

Spark架构示意图:

                Spark的基本知识_第1张图片

Spark各个核心组件介绍:

Client:客户端进程,负责提交作业。

Driver:一个spark作业有一个spark context,一个spark context对于一个driver进程。作业main函数运行在driver中。driver重要负责作业的解析,以及通过DAGScheduler划分stage,将stage转化成TaskSet提交给TaskScheduler任务调度器,进而调度Task到Executor上执行。

Executor:负责执行driver分发的task任务,集群中一个节点可以启动多个Executor,每一个Executor可以执行多个task任务。

cache:spark提供了对rdd不同级别的缓存策略,分别可以缓存到内存,磁盘,外部分布式内存存储系统Tachyon等。

Application:提交一个作业就是一个Application,一个Application只有一个spark context。

Job:rdd执行Action操作就会生成一个job。

Task:spark运行的基本单位,负责处理rdd计算逻辑。

Stage:DAGScheduler将job划分为多个stage,stage划分界限是shuffle的产生,shuffle标志着上一个stage的结束和下一个stage的开始。

TaskSet:划分的stage会转换成一组相关联的任务集。

RDD(Resilient Distributed Dataset):弹性分布式数据集,可以理解为一种只读分布式多分区的数组,spark计算操作都是基于rdd进行的。

DAG(Directed Acyclic Graph):有向无环图。spark实现了DAG计算模型,DAG计算模型指将一个计算任务按照规则分解为若干子任务,这些任务之间根据逻辑关系构建成有向无环图。

三、RDD介绍

  缓存、依赖关系

(1)计算类型

在Spark中RDD提供Transformation和Action两种计算类型。Transformation操作非常丰富,采用延迟执行的方式,在逻辑上定义了RDD的依赖关系和计算逻辑,但并不会真正触发执行动作,只有等到Action操作才会真正触发执行操作。Action操作用于最终结果的输出。

从HDFS文件生成Spark RDD,经过map,join等多次Transformation操作,最终调用saveAsTextFile Action操作将结果集输出到HDFS并以文件形式保存。RDD的流转过程如下图:

                  Spark的基本知识_第2张图片

(2)缓存

在spark中RDD可以缓存到内存或者磁盘上,提供缓存的主要目的是减少同一数据集被多次使用的网络传输次数,提高spark计算性能。

spark提供对RDD的多种缓存级别,可以满足不同场景对RDD的使用需求。RDD的缓存具有容错性,如果有分区丢失,可以通过系统自动重新计算。

在代码中可以使用persist()方法或cache()方法缓存RDD。cache()方法默认将RDD缓存到内存中,cache()方法和persist()方法都可以使用unpersist()方法来取消RDD缓存。

(3)依赖关系

窄依赖(Narrow Dependency):父RDD的分区只对应一个RDD分区,如果子RDD只有部分分区数据损坏或者丢失,只需要从对应的父RDD重新计算恢复。

                           Spark的基本知识_第3张图片

宽依赖(Shuffle Dependency):子RDD分区依赖父RDD的所有分区,如果子RDD部分分区甚至全部分区数据损坏或丢失,需要从所有父RDD重新计算,相对窄依赖而言付出代价更高,所以应尽量避免宽依赖的使用。

                                                 Spark的基本知识_第4张图片

Lineage:每个RDD都会记录自己依赖的父RDD信息,一旦出现数据损坏或者丢失将从父RDD迅速重新恢复。

四、运行模式

spark运行模式主要有以下几种:

  (1) Local模式:本地采用多线程的方式执行,主要用于开发测试。

(2)On Yarn模式Spark On Yarn有两种模式,分别为yarn-client和yarn-cluster模式。yarn-client模式中,Driver运行在客户端,其作业运行日志在客户端查看,适合返回小数据量结果集交互场景使用。yarn-cluster模式中,Driver运行在集群中的某个节点,节点的选择由YARN调度,作业日志通过yarn管理名称查看,也可以在YARN的Web UI查看,适合大数据量非交互式场景使用。

作业在yarn-cluster模式下执行过程:

                    Spark的基本知识_第5张图片

(1)Client在任何一台能与Yarn通信的入口机向Yarn提交作业,提交的配置中可以设置申请资源情况,如果没有配置则将采用默认配置。

(2)RsourceManager接收到Client的作业请求后,首先检查程序启动的ApplicationMaster需要资源情况,然后向资源调度器申请选取一个能够满足资源要求的NodeManager节点用于启动ApplicationMaster进程,ApplicationMaster启动成功之后立即在该节点启动Driver进程。

(3)ApplicationMaster根据提交作业时设置的Executor相关配置参数或者默认配置参数与ResourceManager通信领取Executor资源信息,并与相关NodeManager通信启动Executor进程。

(4)Executor启动成功之后与Driver通信领取Driver分发的任务。

(5)Task执行,运行成功输出结果。

五、Shuffle详解

Spark是实现了MapReduce原语的一种通用实时计算框架。Spark作业中Map阶段的Shuffle称为Shuffle Write,Reduce阶段的Shuffle称为Shuffle Read.

Shuffle Write阶段会将Map Task中间结果数据写入到本地磁盘,而在Shuffle Read阶段中,Reduce Task从Shuffle Write阶段拉取数据到内存中并计算。Spark Shuffle阶段划分方式如图:

                                                           Spark的基本知识_第6张图片

1.Shuffle Write实现方法

(1)基于Hash的实现(hash-based)

每个Map Task都会生成与Reduce Task数据相同的文件数,对Key取Hash值分别写入对于文件中。生成的文件数FileNum=MapTaskNum*ReduceTaskNum,如果Map Task和Reduce Task数都比较多就会生成大量小文件,写文件过程中,每个文件都要占用一部分缓冲区,总占用缓冲区大小TotalBufferSize=CoreNum*ReduceTaskNum*FileBufferSize,大量的小文件就会占用更多的缓冲区,造成不必要的内存开销,同时,大量的随机写操作会大大降低磁盘IO的性能。对此进一步优化,引入了Consolidate(合并)机制。将同一个Core中执行的Task输出结果写入到相同文件中,生成的文件数FileNum=CoreNum*ReduceTaskNum,这样优化方式减少了生成文件数,提高了磁盘IO的吞吐量,但是文件缓存占用的空间并没有减少,性能没有得到明显有效提高。

基于hash的优缺点:

优点:实现简单,小数量级数据处理操作方便

缺点:产生小文件过多,内存利用率低,大量随机读写造成磁盘IO性能下降。

(2)基于sort的实现方式(sort-based)

该方式中每个Map Task任务生成两个文件,一个是数据文件,一个是索引文件,生成的文件数FileNum=MapTaskNum*2。数据文件中的数据按照Key分区在不同分区之间排序,同一分区中的数据不排序,索引文件记录了文件中每个分区的偏移量和范围。当Reduce Task读取数据时,先读取索引文件找到对应的分区数据偏移量和范围,然后从数据文件读取指定数据。

基于Sort的实现方式的优缺点:

优点:顺序读写能大幅度提高磁盘IO性能,不会产生过多小文件,降低文件缓存占用内存空间大小,提高内存使用率。

缺点:多了一次粗粒度的排序。

2.Shuffle Read的实现方式

Shuffle Read阶段中Task通过直接读取本地Shuffle Write阶段产生的中间结果数据或者通过HTTP的方式从远程Shuffle Write阶段拉取中间结果数据进行处理。Shuffle Write阶段基于Hash和基于Sort两种实现方式的中间结果数据在Shuffle Read阶段采取同一种实现方式。

1)获取需要拉取的数据信息,根据数据本地性原则判断曹勇哪种级别拉取方式。

2)判断是否需要在Map端聚合(reduceByKey会在Map端预聚合。)

3)Shuffle Read阶段Task拉取过来的数据如果涉及聚合或排序,则会使用HashMap结构在内存中存储,如果拉取过来的数据集在HashMap这种已经存在相同的键则将数据聚合在一起。此时涉及一个重要参数--spark.shuffle.spill,决定在内存被写满后是否将数据以文件形式写入到磁盘,默认值为true,如果设置为false,则有可能发生OOM内存溢出的风险,建议开启。

4)排序聚合之后的数据以文件写入磁盘将产生大量的文件内数据有序的小文件,将这些小文件重新加载到内存中,随后采用归并排序的方式合并为一个大的数据文件。

六、Spark SQL

Spark SQL是spark的重要组成模块,也是目前大数据生产环境中使用最广泛的技术之一,主要用于结构化数据处理。Spark先后引入了DataFrame和DataSet两种数据结构,以便更加高效地处理各种数据。

Spark Session:Spark2.0引入了SparkSession,用于在Spark SQL开发过程中初始化上下文,为用户提供统一入口用户可以通过SparkSession API直接创建DataFrame和DataSet。

DataFrame:Spark从1.3版本引入DataFrame,DataFrame是一种带有Schema元信息的分布式数据集,类似于传统数据库中的二维表,定义有字段名称和类型,用户可以像操作数据库表一样使用DataFrame。

创建DataFrame

1)通过读取指定路径文件的方式创建DataFrame,SparkSession支持读取多种文件格式

2)通过RDD转换成DataFrame,需要引入spark.implicits包进行隐式转换。

3)通过JDBC连接数据库,将数据表转换成DataFrame。

2.DataFrame常用操作

1)toDF 函数

作为DataSet的一种特殊形式,DataFrame的toDF函数定义在DataSet类中,函数的作用是将RDD转换为DataFrame。

2)as函数

返回一个指定别名的新DataSet

3)printSchema函数

打印DataFrame的Schema信息

4)show函数

默认以表格形式展现DataFrame数据集的前20行数据,字符串类型数据长度超过20个字符将会被截断,如果需要控制显示的数据条数和字符串截取显示情况,可以使用带有不同参数show方法。

5)createTempView函数和createOrReplaceTempView函数

创建临时视图,临时视图随着创建该视图会话的终止自动删除,不会绑定到任何数据库中,不可以使用“database.view”的方式来引入临时视图。DataFrame提供了两个函数创建视图,分别是createTempView和createOrReplaceTempView。使用createTempView函数创建视图,如果视图名称已经存在会抛出AnalysisException异常;使用createOrReplaceTempView函数创建视图,如果视图名称已经存在将会被新的视图替换覆盖。

6)createGlobalTempView函数

创建全局临时视图,该视图声明周期与spark应用程序声明周期相关联,随着spark应用程序终止自动删除,它与系统保留的数据库“_global_temp”绑定,该视图的引入方式为“_global_temp.view”。

3.DataFrame持久化

Spark提供了DataFrame保存数据的多种方式,DataFrame可以以不同文件格式输出到指定路径,可以保存到hive表,还可以通过JDBC连接输出到数据库表中。DataFrame有四种保存模式:

1)DataFrame保存数据到文件

2)DataFrame保存数据到Hive表

3)DataFrame保存数据到数据表

DataSet:DataSet是一个特定域的强类型的不可变数据集,每个DataSet都有一个非类型化视图DataFrame(DataFrame是DataSet[Row]的一种表示形式)DataFrame可以通过调用as(Encoder)函数转换成DataSet,而DataSet则可以通过调用toDF()函数转换成DataFrame,两者之间可以相互转换。

创建DataSet需要显式提供Encoder把对象序列化为二进制形式进行存储,DataSet使用专门的编译器序列化对象在网络间传输处理。编译器动态生成代码,可以在编译的时候检查类型,不需要将对象反序列化就可以进行过滤、排序等操作,避免了shuffle过程中频繁的序列化和反序列化,有效减少了内存的使用和java对象频繁GC开销。

Strucured Streaming

Strucured Streaming,即结构化流。设计者的意思是将流数据结构化,基于Spark SQL引擎构建可扩展和高容错流处理引擎。使用sparkStreaming处理流数据是将大量连续数据按照时间切分,采用微处理的方式直接操作RDD,需要开发者自主优化提高处理性能。

在容错方面,Structured Streaming通过设置检查点和写入日志等方式确保端到端的一次性容错保证。Structured Streaming提供快速,精确,可扩展,高容错,端到端的流处理服务。对用户来说,Structured Streaming是在静态表上提供了将流计算转换为对无界输入表的增量查询计算。

1.数据源

目前支持的数据源有File Source、Kafka Source、Socket Source三种。

1)File Source

2)Kafka Source

3)Socket Source

2.输出到外部存储

Structured Streaming将计算结果DataSet输出外部存储,DataSet通过调用writeStream()函数返回DataStream Writer对象,DataStream Writer对象内部定义多个函数,用于设置不同的输出属性。

2.1 输出格式

将Structured Streaming计算结果输出到外部存储,提供了两种输出模式:

1)Complete模式:将计算的全量结果数据输出到外部存储或控制台。支持查询类型:聚合计算。

2)Append模式:将最新的增量结果数据输出到外部存储或控制台。支持查询类型:非聚合计算。

2.2 输出Sink

1)File Sink

将计算结果输出到外部文件存储,目前只支持输出Parquent文件,支持端到端的容错,支持“Append”输出模式。

2)Foreach Sink

自定义扩展输出到外部存储的方式,支持端到端的容错,支持所有输出模式。

3)Console Sink

将计算结果输出到控制台,用于小数量集测试使用,支持“Append”和“Complete”和所有输出模式。

4)Memory Sink

将计算结果以表的形式存储到Drive的内存中,用于小数量数据集测试使用,支持“Append”和“Complete”两种输出模式。

七、Spark优化

Spark的计算任务都在内存中进行,数据集在集群中不断被交换传输和计算,影响计算性能的主要瓶颈是CPU、内存、网络等。在硬件资源有限的情况下,使用各种优化手段能加强Spark计算任务性能,有效提高资源利用率。下面分别从数据优化、代码优化和参数优化三部分介绍常用优化方法。

数据优化

1.数据序列优化

2.列式存储格式

3.数据本地性

代码优化

1.RDD持久化复用

2.使用broadcast广播大变量

3.coalesce(numPartitions:Int)函数过滤后小文件合并重分区

4.mapPartition函数降低单条记录处理开销

5.使用reduceByKey替换groupByKey

6.合理设置分区实现join无shuffle

7.sparkStreaming设置合适批处理间隔

参数优化

1.设置合适资源量

2.设置合适JVM参数

3.调整非堆内存

4.shuffle过程优化

5.分区算子合理使用

 

 

你可能感兴趣的:(Spark的基本知识)