Spark原理与实践 | 青训营笔记

112 阅读7分钟

这是我参与「第四届青训营」笔记创作活动的第5天

大数据处理引擎Spark介绍

  • 大数据处理技术栈: 数据 / 存储(HDFS/Kafka等) / 计算 / 应用
  • OLAP系统:presto / ClickHouse / Impala / DORIS

运行架构(master-slave) image.png

  1. Cluster Manager是集群管理器,控制整个集群,监控Worker,负责资源管理和调度。
  2. Worker节点是从节点,在yarn中可以称为Node manager 负责控制计算节点,启动Executor进程
  3. Driver Program相当于一个APP master,负责作业的任务调度,是一个JVM进程。其运行程序的main函数,创建一个spark context上下文
  4. SparkContext是整个应用的上下文,来控制整个应用的生命周期。
  5. 用户会创建一个SparkContext,然后SparkContext会连接到Cluster Manager,Cluster Manager根据用户提交时设置的参数为本次提交去分配计算资源来启动executor。
  6. Driver会将用户程序划分不同的stage,每一个stage会有一组完全相同的task去构成。这些Task会处理一些待处理数据的不同分区。这些创建完成后,Driver会向Executor发送task
  7. Executor接收到task之后,会下载task的运行时依赖,准备好task的执行环境,然后开始执行task。task会不停的将状态告知给driver,driver根据这些状态不断的发送task到executor。

SparkCore 原理解析

当通过spark-submit选用cluster模式去提交任务给外部资源管理器时如yarn,yarn会在NodeManager中创建一个AppMaster。AppMaster用来管理资源,在yarn模式下其相当于driver。Driver会通过DAG/Task Scheduler来管理调度Task

RDD(Resilient Distributed Dataset)的五个特性:

  1. 分区列表: 每个RDD都有不同的分区,每个分区运行在集群的不同节点上。每个分区都会被一个task处理,分区决定了并行计算的一个数量。 从集群创建RDD时,默认的分区数量是其CPU核数。从HDFS创建时默认是分区数是block块数。
  2. 计算函数compute: Spark RDD是以partition为基本单位的,每个RDD都会实现一个compute函数,对具体的partition进行计算。
  3. Dependencies: 每一个RDD都会依赖于其他的RDD / 这时如果部分分区的数据丢失,spark就可以通过依赖关系重新计算丢失的分区数据。而不是对所有RDD都重新的进行分区计算。
  4. option[Partitioner] 实现了两种分区函数,只有Key-value的RDD才会有partitioner: Hash-Partitioner / Range-Partitioner / Partitioner这个函数不但决定了RDD本身的分区数量,也决定了parent RDD shuffle分区时的分区数量。
  5. PreferredLocations: 每一个分区都会有一个优先的分区列表,也就是说会存储每个Partitioner的优先位置。如对于一个HDFS文件,其会存储每个Partitioner块的位置 / 移动数据不如移动计算。尽可能将计算分配到需要吃力的数据块的位置。

RDD高级概念

RDD算子:Transformation算子:生成一个新的RDD / Action算子:触发Job提交

RDD依赖:描述父子RDD之间的依赖关系

  • 窄依赖:OneToOneDependency / RangeDependency (分区是一对一的,但RDD是多对一)/ PruneDependency(列剪枝dependency RDD 是一对多的)
  • 宽依赖:ShuffleDependency / 如果一个子RDD宕机了,可能需要重新计算很多父RDD。所以这时候可以设置一个checkpoint将数据写入checkpoint上,做高可用的持久话存储,后面如果有即诶但宕机,可以直接从checkpoint的RDD重新计算而不用从头到尾。
  • 利用依赖划分stage:遇到shuffleDependency就划分一个stage / 最后一个RDD的partition数量就对应了每一个stage的task的数量。

调度器

在RDD创建时,sparkcontext就会根据RDD对象创建一个DAG,在action算子触发job之后,会将这个DAG提交给DAG Scheduler。DAG Scheduler根据shuffle dependency将DAG分成不同的stage,为每一个stage生成并提交TaskSet到TaskScheduler。TaskScheduler根据调度算法(FIFO/FAIR)对多个TaskSet进行调度,调度到Executor上。

内存机制

Screenshot 2022-08-31 at 9.49.05 PM.png

  • Executor 堆内内存主要有两类:Storage,Execution UnifiedMemoryManager统一管理Storage/Execution内存 两个内存可以互相借用
  • 缓存RDD数据或者广播数据的时候占用的内存是Storage Memory
  • 在shuffle时候占用的内存被划分为Execution Memory
  • User data structure / internal metadata的User Memory
  • 防止OOM的Reserved Memory(300MB)

多任务间内存分配

  • 在一个Executor内,其所有Task是共享JVM内存的。

  • UnifiedMemoryManager统一管理多个并发Task的内存分配。

  • 每个Task获取的内存区间为 1/(2*N) ~ 1/N N为当前Executor中正在并发运行的task数量。如果内存空间不够的话,该任务就会被阻塞,直到有足够的内存空间才会被唤醒。

  • Executor堆外内存:为了提高shuffle时候的排序效率引入了堆外内存。可以直接操作OS的堆外内存,减少不必要的内存开销,或者频繁的GC,扫描回收等。

  • 启动spark进程的时候会设置一些spark.executor.memory的参数,这个参数就是executor运行时并发任务共享的JVM堆内内存。

shuffle机制

在初始化sparkEnv的时候,会在create方法里面创建一个shuffle manager。其会在shuffle RDD的compute逻辑执行的时候,会从spark env中get这个shuffle manager,去get里面具体的函数。

Sort Shuffle Manager: 当join两个表比较大的时候常用sort shuffle manager / 每个MapTask生成一个Shuffle数据文件和一个index文件

解耦合数据计算和数据读取服务:External Shuffle Service

shuffle write的文件被NodeManager中的Shuffle Service托管,共后续ReduceTask进行shuffle fetch

如果Executor空闲,DRA可以进行回收

SparkSQL 原理解析

Screenshot 2022-08-31 at 10.33.52 PM.png

课后拓展阅读: 快速上手

spark工作原理

把RDD分成不同partition的好处是可以并行处理,RDD中的数据都是在内存中的

RDD:弹性:默认放内存中,内存不够的时候放磁盘中 / 分布式: 每个partition分布在集群的不同节点上,从而可以并行处理 / 容错性:可以自动从节点失败汇总恢复过来,因为知道其依赖关系,所以可以重算数据

spark架构原理

Task是Executor负责启动的线程

Driver / Cluster manager / Executor / Task

spark任务的三种提交方式

本地调试 / submit提交 spark-submit --class 项目路径 --master yarn --deploy-mode client --executor-memory 1G --num-executors 1 (Spark Application 提交运行时部署模式 Deploy Mode ,表示的是 Driver Program 运行的地方。要么是提交应用的 Client:client ,要么就是集群中从节点(Standalone:Worker,YARN:NodeManager):cluster 。 默认值为 client,当在实际的开发环境中,尤其是生产环境,使用 cluster 部署模式提交应用运行) / 使用spark-shell,方便在集群环境调试代码(spark context 已经创建好) spark-shell 也可以连接standlone集群,只要--master配置上本地地址就好

  • 开启spark和hadoop的 historyserver进程

bin/mapred --daemon start historyserver

spark比mapreduce的好处在哪:

1.spark把中间计算结果存放在内存中,减少迭代过程中的数据落地,能够实现数据高效共享,迭代运算效率高。mapreduce中的计算中间结果是保存在磁盘上的,这样必然影响整体运行速度。

2.spark容错性高。spark支持DAG图的分布式并行计算(简单介绍以下spark DAG:即有向无环图,描述了任务间的先后依赖关系,spark中rdd经过若干次transform操作,由于transform操作是lazy的,因此,当rdd进行action操作时,rdd间的转换关系也会被提交上去,得到rdd内部的依赖关系,进而根据依赖,划分出不同的stage。

3.spark更加通用。hadoop只提供了map和reduce两种操作,spark提供的操作类型有很多,大致分为转换和行动操作两大类。转换操作包括:map,filter,flatmap,sample,groupbykey,reducebykey,union,join,cogroup,mapvalues,sort,partitionby等多种操作,行动操作包括:collect,reduce,lookup和save等操作