这是我参与「第四届青训营 」笔记创作活动的第5天
5.1 大数据处理引擎Spark介绍
1.大数据处理技术栈
2.常见大数据处理链路
3.开源大数据处理引擎
4.什么是Spark?
官网:
5.Spark版本演进
6.Spark生态与特点
1)统一引擎, 支持多种分布式场景
2)多语言支持
3)可读写丰富数据源
4)丰富灵活的API算子
5)支持K8S/YARN/Mesos资源调度
7.Spark特点-多语言支持
SQL:
Java/Scala:
R:
Python
8.Spark特点-丰富数据源
1)内置datasource:Text/Parquet/ORC/JSON/CSV/JDBC
2)自定义datasource:实现datasourceV1/V2 API HBase/Mongo/ElasticSearch
A community index of third-party packages for Apache Spark:
9.Spark特点-丰富的API/算子
SparkCore->RDD
map/filter/flatMap/mapPartitions
repartition/groupBy/reduceBy/join/aggregate
foreach/foreachPartition
count/max/min
SparkSQL-> DataFrame
select/filter/groupBylaggljoin/union/orderByl...
Hive UDF/自定义UDF
10.Spark运行框架&部署方式
Spark Local Mode
本地测试/单进程多进程模式
spark-sql--master local[*]...
Spark Standalone Mode
需要启动Spark的Standalone集群的Master/Worker spark-sql--master spark://{port}...
On YARN/K8S
依赖外部资源调度器(YARN/K8S)
spark-sql--master yarn ...
spark-sql--master k8s://https://:...
11.spark下载编译
spark包
编译:
下载:官网download
12.spark包概览:
13.spark提交命令
1)环境变量:
2)spark-shell
3)spark-sql
4)pyspark
14.提交一个简单任务
SparkPi scala代码
编译成jar包之后,使用spark-submit提交
15.spark UI
16.spark性能benchmark
TPC-DS/TPC-H benchmark github.com/databricks/…
5.2 SparkCore 原理解析
1.sparkcore
2.什么是RDD?
RDD(Resilient Distributed Dataset)
Represents an immutable, partitioned collection of elements that can be operated on in parallel.是spark中一个最基本的数据处理模型,分区决定了数量。
abstract class RDD {
def getPartitions: Array[Partition]...
def compute(split: Partition...
def getDependencies: Seq[Dependency[_]]...
val partitioner: Option[Partitioner]..
def getPreferredLocations(split: Partition)...
//算子
def map(f: T => U): RDD[U]
def filter(f: T => Boolean): RDD[T]
...
def count(): Long
def cache() //缓存
def persist() //缓存
描述RDD的五要素
分区列表:每一个RDD都有多个分区,运行在不同节点上,每一个分区都会被一个计算任务处理。分区决定了并行计算的数量,创建RDD的时候可以指定它的分区个数,否则将按照默认值;
函数:RDD以partition为基本单位,每个RDD都会实现一个函数,对具体的partition进行计算。
依赖性:每一个RDD都会依赖于其他的RDD,每次转换都会生成一个新的RDD,进而形成一种前后依赖的关系。
实现两种类型的分区函数:基于哈希,基于范围的分区;
每个分区有一个优先的列表:尽可能将计算分配到需要处理的数据块的存储位置
算子:RDD成员函数
3.如何创建RDD
1)内置RDD
ShuffleRDD/HadoopRDD/JDBCRDD/KafkaRDD/ UnionRDD/MapPartitionsRD/...
2)自定义RDD
class CustomRDD(...) extends RDD {}
实现五要素对应的函数
4.RDD算子
➢两类RDD算子
Transform 算子:生成一个新的RDD
map/filter/flatMap/groupByKey/reduceByKey/...
Action算子:触发Job提交
collect/count/take/saveAs TextFile/.
5.RDD依赖
RDD依赖:描述父子RDD之间的依赖关系(lineage)。
➢窄依赖:父RDD的每个partition至多对应一个子 RDD分区。
NarrowDependency(窄依赖)
def getParents(partitionld: Int): Seq[Int]
One ToOneDependency(一对一)
override def getParents(partitionld: Int): List[Int] = List(partitionld)
RangeDependency
overide def getParents(partitionld: Int): List[Int] = if (partitionld >= outStart && partitionld < outStart + length) List(partitionld -outStart + inStart)
PruneDependency
➢宽依赖:父RDD的每个parition都可能对应多个子RDD分区。
ShuffleDependency
partition一对一,RDD可能一对一,可能一对多
6.RDD执行流程
Job:RDD action算子触发 Stage:依据宽依赖划分 Task:Stage内执行单个partition任务
7.Scheduler
根据ShufleDependency切分Stage,并按照依赖顺序调度Stage,为每个Stage生成并提交TaskSet到TaskScheduler
根据调度算法(FIFO/FAIR)对多个TaskSet进行调度,对于调度到的TaskSet,会将Task调度(locality)到相关Executor上面执行,Executor SchedulerBackend提供
Locality: PROCESS LOCAL, NODE LOCAL, RACK LOCAL, ANY
8.Memory Management
➢Executor内存主要有两类: Storage、 Execution
➢UnifiedMemoryManager 统管理Storage/Execution内存
➢Storage 和Execution内存使用是动态调整,可以相互借用
➢当Storage 空闲,Execution 可以借用Storage的内存使用,
➢可以减少spil等操作,Execution 使用的内存不能被Storage驱逐
➢当Execution 空闲,Storage 可以借用Execution的内存使用,
➢当Execution需要内存时,可以驱逐被Storage借用的内存,直到
➢spark.memory storageFraction边界
UnifedMemoryManager统一管理多 个并发Task的内存分配每个Task获取的内存区间为1/(2*N) ~ 1/N,N为当前Executor中正在并发运行的task数量
9.Shuffle
spark.shuffle.manager -> sort
trait ShuffleManager {
def registerShuffle...
def getWriter...
def getReader..
def unregisterShuffle... } class SortShuffleManager extends ShuffleManager
SortShuffleManager
每个MapTask生成一个 Shuffle数据文件和一个index文件
dataFile中的数据按照partitionld进行排序,
同一个partitionld的数据聚集在一起
indexFile保存了所有paritionld在dataFlle中的位置信息,方便后续ReduceTask能Fetch到对应partitionld 的数据
shuffle write的文件被nodemanager中的shuffle service托管,供后续Reduce Task进行shuffle fetch,如果Executor空闲,DRA可以进行回收
5.3 SparkSQL原理解析
1.Catalyst优化器
2.Catalyst-RBO
Rule Based Optimizer(RBO)
Batch 执行策略
Once->只执行一次
FixedPoint->重复执行,直到Plan不再改变,或者执行达到固定次数(默认100次)
transformDown先序遍历树进行规则匹配 transformUp后序遍历树进行规则匹配
3.Adaptive Query Execution(AQE)(自适应)
每个Task结束会发送MapStatus信息给Driver,边查询边优化
Task的MapStatus中包含当前Task Shuffle产生的每个Partition的size统计信息
Driver获取到执行完的Stages的MapStatus信息之后,按照MapStatus中partition大小信息识别匹配一些优化场景,然后对后续未执行的Plan进行优化
目前支持的优化场景: Partiton合并, 优化shuffle读取,减少reduce task个数SMJ -> BHJ Skew Join优化
4.AQE一Coalescing Shuffle Partitions
Partition合并(coalescing shufle partitions)
问题
spark. Sql shuffle partition作业粒度参数,一个作业中所有Stage都一样,但是每个Stage实际处理的数据不一样,可能某些Stage的性能比较差,比如:partition参数对某个Stage过大,则可能单个partition的大小比较小,而且Task个数会比较多,shufle fetch阶段产生大量的小块的随机读,影响性能
parition参数对某个Stage过小,则可能单个parition的大小比较大,会产生更多的pi或者OOM
作业运行过程中,根据前面运行完的Stage的MapStatus中实际的partiton大小信息,可以将多个相邻的较小的partiton进行动态合并,由一个Task读取进行处理
spark.sql.adaptive.coalescePartitions.enabled
spark.sql.adaptive.coalescePartitions.initialPartitionNum
spark.sql.adaptive.advisoryPartitionSizelnBytes
...
5.AQE一Switching Join Strategies
SortMergeJoin (SMJ) -> BroadcastHashJoin (BHJ)
问题 Catalyst Optimizer优化阶段,算子的statistics估算不准确,生成的执行计划并不是最优
AQE运行过程中动态获取准确Join的leftChild/rightChild的实际大小,将SMJ转换为BHJ
6.AQE - Optimizing Skew Joins
Skew Join
AQE根据MapStatus信息自动检测是否有倾斜,将大的partition拆分成多个Task进行Join
spark.sql.adaptive.skewJoin.enabled
spark.sql.adaptive.skewJoin.skewedPartitionFactor
spark.sql adaptive.skewJoin.skewedPartitionThresholdInBytes
7.Runtime Filter
8.Bloom Runtime Filter
tpcds/q16.sql:链接 AND cs1.cs_call_center_sk=CC_call_center_sk
9.Codegen-Expression(表达式)
select (a+1)*a from t
将表达式中的大量虚函数调用压平到一个函数内部,类似手写代码
动态生成代码,Janino即时编译执行
10.Codegen一WholeStageCodegen
算子/WholeStageCodegen
select (a+1)* a fromt where a = 1
火山模型(Volcano)
算子之间大量的虚函数调用,开销大,将同一个Stage中的多个算子压平到一个函数内部进行执行
动态生成代码,Janino即时编译执行
算子/WholeStageCodegen
一个SQL包含多个Stage的WholeStageCodegen
5.4 业界挑战与实践
1.Shuffle稳定性问题
在大规模作业下,开源ExternalShufleService(ESS)的实现机制容易带来大量随机读导致的磁盘IOPS瓶颈、Fetch请求积压等问题,进而导致运算过程中经常会出现Stage重算甚至作业失败,继而引起资源使用的恶性循环,严重影响SLA.
解决方案
2.SQL执行性能问题
➢压榨CPU资源
CPU流水线/分支预测乱序执行/SIMD/CPU缓存友好/...
Vectorized / Codegen ?
C++ / Java ?
解决方向
Python:C++实现的向量化执行引擎
Intel: OAP/gazelle_ plugin github.com/oap-project…
3.参数推荐/作业诊断
Spark参数很多,资源类/Shfle/Join/Agg/...调参难度大,参数不合理的作业,对资源利用率/Shuffle稳定性/性能有非常大影响,同时,线上作业失败运行慢,用户排查难度大->自动参数推荐/作业诊断