往期推荐
浅谈维度建模、数据分析模型,何为数据仓库,与数据库的区别-CSDN博客
数仓架构:离线数仓、实时数仓Lambda和Kappa、湖仓一体数据湖-CSDN博客
DW层的数仓建模:范式建模、维度建模及数据分析模型、实体建模-CSDN博客
数仓分层ODS、DWD、DWM、DWS、DIM、DM、ADS_dm ads-CSDN博客
后续考虑,会出Spark调优、shuffle、数据倾斜优化等
目录
2.1.4.1 Transformation(转换)算子概述
2.2.4 Spark SQL数据模型 DataFrame和Dataset
1. Spark简介
Spark 于 2009 年诞生于加州大学伯克利分校 AMPLab,2013 年被捐赠给 Apache 软件基金会,2014 年 2 月成为 Apache 的顶级项目。
相对于 MapReduce 的批处理计算,Spark基于内存计算,可以带来上百倍的性能提升,因此它成为继 MapReduce 之后,最为广泛使用的分布式计算框架、大数据分析引擎。
1.1 Spark特点
- 快:采用DAG执行引擎,支持循环数据流和内存计算,使得 Spark 速度更快,在内存中的速度 是Hadoop MR的百倍,在磁盘上的速度是Hadoop MR的十倍(官网数据)。
- 通用:Spark提供了统一的解决方案。Spark可以⽤于批处理、交互式查询(Spark SQL)、实时流处理(Spark Streaming)、机器学习(Spark MLlib)和图计算(GraphX)。这些不同类型的处理都可以在同⼀个应用中无缝使用。
- 易用:Spark支持Java、Python、Scala的API和超过80种⾼级算法,⽽且⽀持交互式的Python和Scala的shell。
- 兼容:Spark可以使⽤Hadoop的YARN和Apache Mesos作为它的资源管理和调度器,器,并且不需要任何数据迁移就可以处理所有Hadoop支持的数据,包括HDFS、HBase和Cassandra等。Spark也可以不依赖于第三⽅的资源管理和调度器,它实现了Standalone作为其内置的资源管理和调度框架。
1.2 Spark和MR处理任务对比
2. Spark组件
2.1 Spark Core
Spark Core实现了 Spark 的基本功能,包含任务调度、内存管理、错误恢复、与存储系统 交互等模块。Spark Core 中还包含 了对弹性分布式数据集(resilient distributed dataset,简称RDD)的 API 定义。
2.1.1 RDD算子
2.1.1.1 为什么有RDD?
在许多迭代式算法(比如机器学习、图算法等)和交互式数据挖掘中,不同计算阶段之间会重用中间结果,即一个阶段的输出结果会作为下一个阶段的输入。但是, 之前的 MapReduce 框架采用非循环式的数据流模型,把中间结果写入到 HDFS 中,带来了大量的数据复制、磁盘 IO 和序列化开销,且这些框架只能支持一些 特定的计算模式(map/reduce),并没有提供一种通用的数据抽象。
RDD 提供了一个抽象的数据模型,让我们不必担心底层数据的分布式特性,只需将具体的应用逻辑表达为一系列转换操作(函数),不同 RDD 之间的转换操作之间还可以形成依赖关系,进而实现管道化,从而避免了中间结果的存储,大大降低数据复制、磁盘 IO 和序列化开销,并且还提供了更多的 API操作!
2.1.1.2 RDD介绍
- RDD(Resilient Distributed Dataset)叫做弹性分布式数据集,是Spark中最基本的数据抽象,是Spark计算的基石,它代表⼀个不可变、可分区、里面的元素可并行计算的集合。
- RDD具有数据流模型的特点:自动容错、位置感知性调度和可伸缩性。RDD允许用户在执⾏多个查询时显式地将⼯作集缓存在内存中,后续的查询能够重⽤⼯作集,这极⼤地提升了查询速度。
- MR中对数据是没有进行抽象的,而在Spark中对数据进行了抽象,提供⼀些列处理⽅法也就是 RDD,为用户屏蔽了底层对数据的复杂抽象和处理,为⽤户提供了⼀组⽅便 的数据转换与求值方法,好比Java中类的封装。
注意 : RDD本身是不存储数据,而是记录了数据的位置,数据的转换关系(调用什么方法、传入什么函数)!!!
以下是RDD源码翻译解读:
2.1.2 RDD 特点
- 弹性体现:
1. 存储的弹性:内存与磁盘的自动切换;
2. 容错的弹性:RDD的血统(Lineag)会记录RDD的元数据信息和转换行为,当RDD的部分分区数据丢失时,它可以根据这些信息来重新运算并恢复丢失的数据分区。
3. 计算的弹性:计算出错重试机制;
4. 分片的弹性:可根据需要重新分片;- 分布式:数据存储在大数据集群不同节点上
- 数据集:RDD封装了计算逻辑,并不保存数据
- 数据抽象:RDD是⼀个抽象,需要具体实现
- 不可变:RDD封装的计算逻辑不可改变,想要改变只能产⽣新的RDD
- 可分区、并行计算
2.1.3 RDD做了什么
从计算的角度来讲,数据处理过程中需要计算资源(内存 & CPU)和计算模型(逻辑)。执⾏时,需要将计算资源 和计算模型进行协调和整合。
Spark框架在执行时,先申请资源,然后将应⽤程序的数据处理逻辑分解成⼀个⼀个的计算任务。然后将任务分发到已经分配资源的计算节点上, 按照指定的计算模型进行数据计算。最后得到计算结果。
2.1.4 RDD的转换和行动操作
- RDD算子分为两种类型的操作:转换操作和行动操作
- 转换操作是返回⼀个新的RDD的操作,比如map和 flatMap
- 行动操作则是向Driver返回结果或将结果写出到外部存在设备,比如collect和saveAsTextFile
2.1.4.1 Transformation(转换)算子概述
RDD中的所有转换都是延迟加载的,它们只是记住这些应⽤到基础数据集上的转换动作,并不会直接计算结果。只有当发生⼀个要求返回结果给Driver的动作时,这些转换才会真正运 行。这样可以在 Action 时对 RDD 操作形成DAG 有向无环图进行 Stage 的划分和并行优化,这这种设计让Spark更加有效率地运行! 列举部分算子:
2.1.4.2 Action(行动)算子概述
在RDD上运⾏计算,并返回结果给Driver或写入文件系统, 列举部分算子:
2.1.5 RDD持久化和缓存
- Spark速度非常快的原因之⼀,就是在不同操作中可以在内存中持久化或缓存多个数据集。当持久化某个RDD后, 每⼀个节点都将把计算的分片结果保存在内存中,并在对此RDD或衍⽣出的RDD进行的其他动作中重⽤,这使得后续的动作变得更加迅速!
- 缓存是Spark构建迭代式算法和快速交互式查询的关键。如果⼀个有持久化数据的节点发⽣故障,Spark 会在需要⽤到缓存的数据时重算丢失的数据分区。如果希望节点故障的情况不会拖累我们的执⾏速度,也可以把数据备份到多个节点上。
- RDD 通过 persist 或 cache 方法可以将前面的计算结果缓存,但是并不是这两个方法被调用时立即缓存,而是触发后面的 action 时,该 RDD 将会被缓存在 计算节点的内存中,并供后面重用。
2.1.6 存储级别
默认的存储级别都是仅在内存存储一份,Spark 的存储级别还有好多种,存储级别在 object StorageLevel 中定义的。
2.1.7 Checkpoint检查点机制
Spark中对于数据的保存除了持久化操作之外,还提供了⼀种检查点的机制,检查点(本质是通过将RDD写入Disk 做检查点)是为了通过血统(lineage)做持久化容错的辅助,lineage过长会造成容错成本过高,这样就不如在中间阶段做检查点容错,如果之后有节点出现问题⽽丢失分区,从做检查点的RDD开始重做Lineage,就会减少资源开销。检查点通过将数据写⼊到HDFS文件系统实现了RDD的检查点功能。
2.1.8 RDD宽窄依赖
RDD 和 它依赖的父 RDD 的关系有两种不同的类型,
宽依赖(wide dependency/shuffle dependency) :父 RDD 的一个分区被子 RDD 的多个分区依赖(涉及到 shuffle)
窄依赖(narrow dependency):父 RDD 的一个分区只会被子 RDD 的一个分区依赖;
2.1.8.1 为什么要设计宽窄依赖
对于窄依赖: 窄依赖的多个分区可以并行计算;窄依赖的一个分区的数据如果丢失只需要重新计算对应的分区的数据就可以了。
对于宽依赖: 划分 Stage(阶段)的依据,对于宽依赖,必须等到上一阶段计算完成才能计算下 一阶段。
2.1.8.2 DAG生成和划分Stage
- DAG是什么?
DAG(有向无环图)指的是数据转换执行的过程,有方向,无闭环(其实就是 RDD 执行的流程);原始的 RDD 通过一系列的转换操作就形成了 DAG 有向无环图,任务执行时,可以按照 DAG 的描述,执行真正的计算(数据被操作的一个过程)。- DAG 的边界
开始:通过 SparkContext 创建的 RDD
结束:触发 Action,一旦触发 Action 就会形成一个完整的 DAG
DAG 划分 Stage
- 一个 Spark 程序可以有多个 DAG(有几个 Action,就有几个 DAG)。
- 一个 DAG 可以有多个 Stage(根据宽依赖/shuffle 进行划分)。
- 同一个 Stage 可以有多个 Task 并行执行(task 数=分区数,如上图,Stage1 中 有三个分区 P1、P2、P3,对应的也有三个 Task)。
- 可以看到这个 DAG 中 reduceByKey 操作是一个宽依赖,Spark 内核会以此为边界将其前后划分成不同的 Stage。 同时在图 Stage1 中,从 textFile 到 flatMap 到 map 都是窄依赖,这几步操作可以形成一个流水线操作,通过 flatMap 操作生成partition 不用等待整个 RDD 计算结束,可以直接进行 map 操作,这样大大 提高了计算的效率。
2.2 Spark SQL
2.2.1 Spark SQL发展(精彩)
Spark SQL是构建在SparkCore基础之上的⼀个基于SQL的计算模块。 SparkSQL的前身叫【Shark】,最开始Shark的底层代码优化、sql的解析、执行引擎等完全基于Hive(Shark On Hive),Hive实现了SQL on Hadoop,使用 MapReduce 执行任务,但是使用MapReduce做计算(Hive On MR),使得Hive 的查询延迟比较高,而Shark改写 Hive 的物理执行计划,使用 Shark 代替 MapReduce 物理引擎(Hive On Shark),使用列式内存存储,使得Shark执行速度比Hive快,然而Shark 执行计划的生成严重依赖 Hive(Shark On Hive On Shark),想要增加新的优化非常困难; 并且Hive 是进程级别的并行,Spark 是线程级别的并行,所以 Hive 中很多线程不安全的代码不适用于 Shark,所以在15年中旬的时候,Shark负责⼈,将Shark项⽬结束掉,重新独⽴出来的⼀个项⽬,就是SparkSQL,不再依赖Hive,此后逐渐的形成两条互相独立的业务:SparkSQL和Hive-On-Spark。
如果说Hive是将SQL转化为MR,那么SparkSQL是将SQL转换成RDD+优化执行,因为我们直接操作RDD需要编程实现(学习成本),有了SQL我们即使不懂编程也可以实现RDD计算!
2.2.2 Spark SQL概述
Spark SQL主要用于结构化数据(数据分为结构化数据、半结构化数据、非结构化数据)RDD主要用于处理非结构化、半结构化、结构化数据。与RDD API编程式操作不同,Spark SQL可以使用SQL完成数据分析计算,Spark SQL提供的接口为 Spark提供了有关数据结构和正在执⾏的计算的更多信息。在内部,Spark SQL使⽤这些额外的信息来执⾏额外的优化。有几种与Spark SQL交互的⽅法,包括SQL和Dataset API。计算结果时,将使⽤相同的执⾏引擎,这与⽤于表示计算的API/语⾔⽆关。这种统⼀意味着开发⼈员可以轻松地在不同的API之间来回切换,基于API的切换提供了表示给定转换的最⾃然的⽅式。
2.2.3 Spark SQL特点
- 集成性
- 统一性
- 集成Hive
- 支持多种数据源
2.2.4 Spark SQL数据模型 DataFrame和Dataset
我们可以通过两种方式使用Spark,一种是命令式,使用Spark shell编程操作RDD,另一种是通过SparkSQL的数据模型DataFrame和Dataset
- DataFrame和Dataset 可以理解为是⼀张mysql中的⼆维表,表有什么?表头,表名,字段,字段类型。RDD其实说白了也是⼀张二维表,但是这张二维表相比较于DataFrame和Dataset却少了很多东西,比如表头,表名,字段,字段类型,只有数据和操作数据的方法。
- DataFrame是1.3的时候出现的,Dataset是在spark 1.6.2出现的,早期的时候DataFrame叫 SchemaRDD,SchemaRDD和RDD相比,就多了Schema,所谓元数据信息。相比DataFrame,Dataset提供了编译时类型检查,对于分布式程序来讲,提交⼀次作业要编译、打包、上传、运行,到提交到集群运行时才发现错误,很麻烦,这也是引⼊Dataset的⼀个重要原因!
- ⼀般的,将RDD称之为Spark体系中的第一代编程模型;DataFrame比RDD多了⼀个Schema元数据信息,被称之为Spark体系中的第⼆代编程模型;Dataset吸收了RDD的优点(强类型推断、函数式编程)和DataFrame中的优化(SQL优化引擎、内存列存储),成为Spark的最新⼀代的编程模型。
2.2.5 如何进行SparkSQL编程
- Spark Core中,如果想要执行应用程序,需要首先构建上下文环境对象SparkContext,Spark SQL其实可以理解为对Spark Core的⼀种封装,不仅仅在模型上进行了封装,上下文环境对象也进行了封装。
- 在老的版本中,SparkSQL提供两种SQL查询起始点:⼀个叫SQLContext,⽤于Spark自己提供的SQL查询; ⼀个叫HiveContext,⽤于连接Hive的查询。
- SparkSession是Spark最新的SQL查询起始点,实质上是SQLContext和HiveContext的组合,所以在 SQLContex和HiveContext上可⽤的API在SparkSession上同样是可以使⽤的。
- SparkSession内部封装了 SparkContext,所以计算实际上是由sparkContext完成的。 构建SparkSession需要依赖SparkConf或者SparkContext,可以使⽤⼯⼚构建器(Builder⽅式)模式创建 SparkSession。
2.3 Spark Streaming
2.3.1 简介
- Spark Streaming 是 Spark 提供的对实时数据进行流式计算(实时计算)的组件。提供了用来操作数据流的 API,并且与 Spark Core 中的 RDD API 高度对应。
- 从计算的延迟上⾯,又可以分为纯实时流式计算和准实时流式计算,SparkStreaming属于准实时计算框架
- 所谓纯实时的计算,指的是来⼀条记录(event事件),启动⼀次计算的作业;离线计算指的是每次计算非常大的⼀批(比如几百G,好几个T)数据;准实时则是介于纯实时和离线计算之间的⼀种计算方式,那就是微批处理,即把大量数据微分成多小批进行计算,近似看成流计算。
2.3.2 流式计算特点
- 数据是无界的(unbounded)
- 数据是动态的
- 计算速度快
- 计算不止一次
- 计算不能终止
离线计算特点:
- 数据是有界的(Bounded)
- 数据静态的
- 计算速度通常较慢
- 计算只执⾏⼀次
- 计算终会终⽌
2.3.3 常见流式计算和离线计算框架
离线
- mapreduce
- spark-core
- flink的dataset
流式
- storm 第⼀代的流式处理框架
- sparkStreaming(其实是为微批处理)第二代的流式处理框架
- flink的datastream 第三代的流式处理框架
2.3.4 SparkStreaming的基本工作原理
SparkCore的数据模型是RDD,SparkSQL数据模型是DataFrame和DataSet,SparkStreaming的数据模型是DStream,DStream和RDD一样,是一种高级抽象,它基于内存处理连续的数据流,本质上还是RDD的基于内存的计算。
- 接收实时输入数据流,然后将数据拆分成多个batch,比如每收集1秒的数据封装为⼀个batch,然后将每个 batch交给Spark的计算引擎进行处理,最后会⽣产出⼀个结果数据流,其中的数据,也是由一个一个的batch所组成的。
- DStream,英⽂全称为Discretized Stream,中文翻译为“离散流”,它代表了⼀个持续不断的数据流。DStream可以通过输入数据源来创建,比如Kafka、Flume、ZMQ和 Kinesis;也可以通过对其他DStream应用高阶函数来创建,比如map、reduce、join、window。
- DStream的内部,其实是一系列时间上连续的RDD。DStream中的每个RDD都包含了⼀个时间段内的数据。
- 对DStream应⽤的算子,比如map,其实在底层会被翻译为对DStream中每个RDD的操作。比如对⼀个DStream执行⼀个map操作,会产生⼀个新的DStream。但是,在底层,其实是对输入DStream中每个时间段的RDD,都来⼀遍map操作,然后⽣成的新的RDD,即作为新的DStream中的那个时间段的⼀个RDD。
2.3.5 SparkStreaming的缓存
SparkStreaming的缓存,说白了就是DStream的缓存,DStream的缓存就只有⼀个⽅⾯,那就是DStream对应的RDD缓存,RDD如何缓存?rdd.persist(),所以DStream的缓存说⽩了就是RDD的缓存,使⽤persist()指定,并指定持久化策略,⼤多算⼦默认情况下,持久化策略为MEMORY_AND_DISK_SER_2
2.3.6 SparkStreaming的容错
- 每⼀个Spark Streaming应⽤,正常来说都是要7*24⼩时运转的,这也是实时计算程序的特点。因为要持续不断的对数据进⾏计算,因此对实时计算应⽤的要求必须进行容错保底。
- Spark Streaming程序就必须将足够的信息checkpoint到容错的存储系统上,从⽽让它能够从失败中进行恢复。有两种数据需要被checkpoint:
- 元数据checkpoint:将定义了流式计算逻辑的信息,保存到容错的存储系统上,⽐如HDFS。当运行Spark Streaming应⽤程序的Driver进程所在节点失败时,该信息可以⽤于进⾏恢复。元数据信息包括了: 创建Spark Streaming应⽤程序的配置信息,比如SparkConf中的信息。 定义了Spark Stream应⽤程序的计算逻辑的DStream操作信息。 定义了那些job正在排队,还未处理的batch信息。
- 数据checkpoint:将实时计算过程中产生的RDD的数据保存到可靠的存储系统中。 对于一些将多个batch的数据进⾏聚合的,有状态的transformation操作,这是⾮常有⽤的。在这种 transformation操作中,生成的RDD是依赖于之前的batch的RDD,这会导致随着时间的推移,RDD的依赖链条变得越来越长。 要避免由于依赖链条越来越长,导致的⼀起变得越来越长的失败恢复时间,有状态的transformation操作执⾏过程中间产⽣的RDD,会定期地被checkpoint到可靠的存储系统上,比如HDFS。从而削减RDD的依赖链条,进而缩短失败恢复时,RDD的恢复时间。
2.3.7 DStream操作
DStream 上的操作与 RDD 的类似,分为以下两种:
- Transformations(转换)
无状态转换:每批次处理不依赖于之前批次的数据
有状态转换:当前批次的处理需要使用之前批次的数据或者中间结果,有状态转换包括基于追踪状态变化的转换(updateStateByKey)和滑动窗口的转换:
- Output Operations(输出)/Action
Output Operations 可以将 DStream 的数据输出到外部的数据库或文件系统。 当某个 Output Operations 被调用时,spark streaming 程序才会开始真正的 计算过程(与 RDD 的 Action 类似)。
2.4 MLlib
提供常见的机器学习(ML)功能的程序库。包括分类、回归、聚类、协同过滤等,还提供了模型评估、数据导入等额 外的⽀持功能
2.5 Graphx
GraphX在Spark基础上提供了一站式的数据解决⽅案,可以⾼效地完成图计算的完整流⽔作业。GraphX是⽤于图 计算和并⾏图计算的新的(alpha)Spark API。通过引⼊弹性分布式属性图(Resilient Distributed Property Graph),⼀种顶点和边都带有属性的有向多重图,扩展了Spark RDD
Spark多种部署模式
- Local 多⽤于本地测试,如在eclipse,idea中写程序测试等。
- Standalone 是Spark⾃带的⼀个资源调度框架,它⽀持完全分布式。
- Yarn ⽣态圈⾥⾯的⼀个资源调度框架,Spark也是可以基于Yarn来计算的。
- Mesos 资源调度框架,与Yarn类似。