Spark 原理与实践 | 青训营笔记
这是我参与「第四届青训营 」笔记创作活动的的第5天,本篇笔记主要是关于第五次大数据课程《Spark 原理与实践》的课堂笔记
Spark介绍
基于内存进行计算,在map Reduce基础上进行优化而来的批式计算引擎
Spark生态组件
- Spark Core:Spark核心组件,它实现了Spark的基本功能,包含任务调度、内存管理、错误恢复、与存储系统交互等模块。
- Spark SQL:用来操作结构化数据的核心组件,通过Spark SQL可以直接查询Hive、HBase等多种外部数据源中的数据。
- Spark Structured Streaming:Spark提供的流式计算框架,支持高吞吐量、可容错处理的实时流式数据处理。
- MLlib:Spark提供的关于机器学习功能的算法程序库,包括分类、回归、聚类、协同过滤算法等,还提供了模型评估、数据导入等额外的功能。
- GraphX:Spark提供的分布式图处理框架,拥有对图计算和图挖掘算法的API接口以及丰富的功能和运算符。
- 独立调度器、Yarn、Mesos、Kubernetes:Spark框架可以高效地在一个到数千个节点之间伸缩计算,集群管理器则主要负责各个节点的资源管理工作,为了实现这样的要求,同时获得最大灵活性,Spark支持在各种集群管理器(Cluster Manager)上运行。
特点:
- 多语言支持
SQL、Java/Scala、R、Python
- 丰富数据源
内置DataSource、自定义DataSource
- 丰富的API/算子
RDD、DataFrame
Spark运行架构
- 具体过程: 用户创建一个SparkContext,SparkContext连接到Cluster Manager,Cluster Manager根据用户提交时设置的参数,为本次提交分配一定的资源,启动Executor。Driver会将用户程序划分为不同的spage,每个spage会有完全相同的Task,这些Task会分别作用于待处理的数据,之后Driver会向Executor发送Task,配置每个Task的执行环境,开始执行Task,知道所有Task都执行正确或超过执行次数限制。
Spark部署方式
- Spark Local Mode:本地测试/单进程多线程模式
- Spark Standalone Mode:需要启动Spark的Standalone集群的Master/Worker
- On YARN/K8S:依赖外部资源调度器(YARN/K8S)
SparkCore
RDD:容错的,可以并行执行的弹性分布式数据集
RDD算子:对任何函数进行某一项操作都可以认为是一个算子,RDD算子是RDD的成员函数
- Transform算子:生成一个新的RDD
- Action算子:触发Job 提交
RDD依赖:描述父子RDD之间的依赖关系。
- 窄依赖:父RDD的每个partition至多对应一个子RDD分区。
- 宽依赖:父RDD的每个partition都可能对应多个子RDD分区。会产生shuffle(数据之间的重分发机制) RDD执行过程:
划分Stage的整体思路:从后往前推,遇到宽依赖就断开,划分为一个Stage。遇到窄依赖,就将这个RDD加入该Stage中,DAG最后一个阶段会为每个结果的Partition生成一个ResultTask。每个Stage里面的Task数量由最后一个RDD的Partition数量决定,其余的阶段会生成ShuffleMapTask。
内存管理
Spark 作为一个基于内存的分布式计算引擎,Spark采用统一内存管理机制。重点在于动态占用机制。
- 设定基本的存储内存(Storage)和执行内存(Execution)区域,该设定确定了双方各自拥有的空间的范围,UnifiedMemoryManager统一管理Storage/Execution内存
- 双方的空间都不足时,则存储到硬盘;若己方空间不足而对方空余时,可借用对方的空间
- 当Storage空闲,Execution可以借用Storage的内存使用,可以减少spill等操作, Execution内存不能被Storage驱逐。Execution内存的空间被Storage内存占用后,可让对方将占用的部分转存到硬盘,然后"归还"借用的空间
- 当Execution空闲,Storage可以借用Execution内存使用,当Execution需要内存时,可以驱逐被Storage借用的内存,可让对方将占用的部分转存到硬盘,然后"归还"借用的空间
SparkSQL
- 执行过程
影响SparkSQL性能两大技术:
- Optimizer:执行计划的优化,目标是找出最优的执行计划
- Runtime:运行时优化,目标是在既定的执行计划下尽可能快的执行完毕。
- 优化策略
- Catalyst优化
- Rule Based Optimizer(RBO)
- Cost Based Optimizer(CBO)
- AQE
- 动态合并shuffle分区(Dynamically coalescing shuffle partitions): 作业运行过程中,根据前面运行完的Stage的MapStatus中实际的partiton大小信息,可以将多个相邻的较小的partiton进行动态合并,由一个Task读取进行处理
- 动态调整Join策略(Dynamically switching join strategies)
- 动态优化数据倾斜Join(Dynamically optimizing skew joins): AQE根据MapStatus信息自动检测是否有倾斜将大的partition拆分成多个Task进行Join
- RuntimeFilter 实现在Catalyst中。动态获取Filter内容做相关优化,当我们将一张大表和一张小表等值连接时,我们可以从小表侧收集一些统计信息,并在执行join前将其用于大表的扫描,进行分区修剪或数据过滤。可以大大提高性能
- Codegen
-
Expression级别 表达式常规递归求值语法树。需要做很多类型匹配、虚函数调用、对象创建等额外逻辑,这些overhead远超对表达式求值本身,为了消除这些overhead,Spark Codegen直接拼成求值表达式的java代码并进行即时编译
-
WholeStage级别
- Catalyst优化