同一个程序创建多个spark_一文盖之spark核心原理

3b50e05317e1590b819a41a4c077855b.png

1.基本定义

Spark是分布式的基于内存的迭代式计算框架,当然它也基于磁盘做迭代计算,具说Spark基于磁盘做迭代计算也会比基于磁盘迭代的MapReduce框架快10余倍;而基于内存迭代计算则比MapReduce迭代快100倍以上。

2.底层原理

33edad9e8533dd569877c22b728e1b6f.png

(1)Application

  • 指的是用户编写的Spark应用程序,包含了Driver功能代码和分布在集群中多个节点上运行的Executor代码

(2)Driver

  • Spark中的Driver即运行上述Application的Main()函数并且创建SparkContext,其中创建SparkContext的目的是为了准备Spark应用程序的运行环境。
  • 在Spark中由SparkContext负责和ClusterManager通信,进行资源的申请、任务的分配和监控等;当Executor部分运行完毕后,Driver负责将SparkContext关闭。

(3)DAGScheduler

  • DAGScheduler把一个spark作业转换成成stage的DAG(Directed Acyclic Graph有向无环图)
  • 根据RDD和stage之间的关系,找出开销最小的调度方法,然后把stage以TaskSet的形式提交给TaskScheduler。

(4)TaskScheduler

  • TaskScheduler维护所有TaskSet,当Executor向Driver发送心跳时,TaskScheduler会根据其资源剩余情况分配相应的Task。
  • 另外TaskScheduler还维护着所有Task的运行状态,重试失败的Task。

(5)Executor

  • Application运行在Worker节点上的一个进程,该进程负责运行Task,并且负责将数据存在内存或者磁盘上,每个Application都有各自独立的一批Executor,

(6) Task

  • 被送到某个Executor上的工作任务;单个分区数据集上的最小处理流程单元。

(7) Job

  • 由一个或多个调度阶段所组成的一次计算作业;包含多个Task组成的并行计算
  • 一个JOB包含多个RDD及作用于相应RDD上的各种Operation

(8) Stage

  • 一个任务集对应的调度阶段
  • 每个Job会被拆分很多组Task,每组任务被称为Stage,也可称TaskSet,一个作业分为多个阶段;Stage分成两种类型ShuffleMapStage、ResultStage。

(9)Rdd

  • RDD(Resilient Distributed Datasets弹性分布式数据集),是spark中最重要的概念
  • 可以简单的把RDD理解成一个提供了许多操作接口的数据集合,和一般数据集不同的是,其实际数据分布存储于一批机器中(内存或磁盘中)

(10)DataFrame

  • DataFrame是一个分布式集合,其中数据被组织为命名的列。它概念上等价于关系数据库中的表,但底层做了更多的优化。
  • DataFrame可以从很多数据源构建,比如:已经存在的RDD、结构化文件、外部数据库、Hive表。

(11)DataSet

  • Dataset可以认为是DataFrame的一个特例,主要区别是Dataset每一个record存储的是一个强类型值而不是一个Row。
  • DataSet可以在编译时检查类型,并且是面向对象的编程接口

3.重要概念

(1)spark on yarn 执行流程

c939636a9615c10e0320d9d4f230fa56.png
  • Spark Yarn Client向YARN的ResourceManager申请启动Application Master。同时在SparkContent初始化中将创建DAGScheduler和TASKScheduler等
  • ResourceManager收到请求后,在集群中选择一个NodeManager,为该应用程序分配第一个Container,要求它在这个Container中启动应用程序的ApplicationMaster
  • Client中的SparkContext初始化完毕后,与ApplicationMaster建立通讯,向ResourceManager注册,根据任务信息向ResourceManager申请资源(Container);
  • 一旦ApplicationMaster申请到资源(也就是Container)后,便与对应的NodeManager通信,要求它在获得的Container中启动Executor,Executor启动后会向Client中的SparkContext注册并申请Task;
  • Client中的SparkContext分配Task给Executor执行,Executor运行Task并向Driver汇报运行的状态和进度,以让Client随时掌握各个任务的运行状态,从而可以在任务失败时重新启动任务;
  • 应用程序运行完成后,Client的SparkContext向ResourceManager申请注销并关闭自己;

(2)深入理解Rdd

(2.1)结构化理解

afa84d3a44a3281d812fe0906e163ec4.png

(2.2)基础特点

  • 是一个分区的只读记录的集合;
  • 一个具有容错机制的特殊集;
  • 只能通过在稳定的存储器或其他RDD上的确定性操作(转换)来创建;
  • 可以分布在集群的节点上,以函数式操作集合的方式,进行各种并行操作

(2.3)弹性特点

  • 基于Lineage的高效容错(第n个节点出错,会从第n-1个节点恢复,血统容错);
  • Task如果失败会自动进行特定次数的重试(默认4次);
  • Stage如果失败会自动进行特定次数的重试(可以值运行计算失败的阶段),只计算失败的数据分片;
  • 数据调度弹性:DAG TASK 和资源管理无关;
  • checkpoint;
  • 自动的进行内存和磁盘数据存储的切换;

(2.4)partition

  • RDD是一个只读的有属性的数据集。属性用来描述当前数据集的状态,数据集是由数据的分区(partition)组成。
  • RDD 内部的数据集合在逻辑上和物理上被划分成多个小子集合,这样的每一个子集合我们将其称为分区(partitions)
  • 分区的个数会决定并行计算的粒度,而每一个分区数值的计算都是在一个单独的任务中进行,因此并行任务的个数,也是由 RDD分区的个数决定的。

(2.5)dependencies

  • 每次transformations操作时,都是重新创建了一个新的RDD2,这个RDD2时基于原有的RDD1,RDD1是RDD2的Parents,也就是说这个RDD2依赖于RDD1。这些依赖描述了RDD的Lineage(血统)
  • 如果父RDD的每个分区最多只能被子RDD的一个分区使用,我们称之为(narrow dependency)窄依赖;
  • 若一个父RDD的每个分区可以被子RDD的多个分区使用,我们称之为(wide dependency)宽依赖,在源代码中方法名为ShuffleDependency,顾名思义这之中还需要Shuffle操作
ce9045f8d12d3aeba5373175b88fd4f1.png

(2.6)Checkpoint

尽管当一个RDD出现问题可以由它的依赖也就是Lineage信息可以用来故障恢复,但对于那些Lineage链较长的RDD来说,这种恢复可能很耗时。

Checkpoint是Spark提供的一种缓存机制,当需要计算的RDD过多时,为了避免重新计算之前的RDD,可以对RDD做Checkpoint处理,检查RDD是否被物化或计算,并将结果持久化到磁盘或HDFS。

  • Checkpoint会把当前RDD保存到一个目录中。
  • Checkpoint的时候,会把所有依赖的父级rdd信息清除掉。
  • Checkpoint不会马上执行,要触发action操作的时候才会执行。
  • 因为 Checkpoint会清除父级RDD的信息,所以在Checkpoint应该先做persist(持久化)操作,否则就要重新计算一遍。
  • 一般来说,Lineage链较长、宽依赖的RDD需要采用检查点机制。

(3)Shuffle详解

Stage之间就是Shuffle,如图groupby 之后的 Map 操作,为了计算相同 key 下的元素个数,需要把相同 key 的元素聚集到同一个 partition 下,所以造成了数据在内存中的重新分布,即 shuffle 操作 。

shuffle 操作是 spark 中最耗时的操作,应尽量避免不必要的 shuffle,Stage1,Stage2和Stag3之间就会产生Shuffle

a118734780a8d2d32912e1c5d8cde0b7.png

在Spark的中,负责shuffle过程的执行、计算和处理的组件主要就是ShuffleManager,也即shuffle管理器。spark的Shuffle有Hash Shuffle和Sort Shuffle两种

(3.1)聚合

reduceByKey会将上一个RDD中的每一个key对应的所有value聚合成一个value,然后生成一个新的RDD,元素类型是对的形式,这样每一个key对应一个聚合起来的value。

  • Shuffle Write:上一个stage的每个map task就必须保证将自己处理的当前分区的数据相同的key写入一个分区文件中,可能会写入多个不同的分区文件中。
  • Shuffle Read:reduce task就会从上一个stage的所有task所在的机器上寻找属于己的那些分区文件,这样就可以保证每一个key所对应的value都会汇聚到同一个节点上去处理和聚合。

(3.2)hashshuffle

  • 执行流程
  • 每一个map task将不同结果写到不同的buffer中,每个buffer的大小为32K。buffer起到数据缓存的作用。新写的磁盘小文件会追加内容。
  • 每个buffer文件最后对应一个磁盘小文件。
  • reduce task来拉取对应的磁盘小文件
  • 总结
  • maptask的计算结果会根据分区器(默认是hashPartitioner)来决定写入到哪一个磁盘小文件中去。ReduceTask会去Map端拉取相应的磁盘小文件。
  • 产生的磁盘小文件的个数:M(map task的个数)*R(reduce task的个数)
  • 问题:
  • 在Shuffle Write过程中会产生很多写磁盘小文件的对象。
  • 在Shuffle Read过程中会产生很多读取磁盘小文件的对象。
  • 在JVM堆内存中对象过多会造成频繁的gc,gc还无法解决运行所需要的内存 的话,就会OOM
  • 在数据传输过程中会有频繁的网络通信,频繁的网络通信出现通信故障的可能性大大增加

(3.3)sortshuffle

  • 执行流程
  • map task 的计算结果会写入到一个内存数据结构里面,内存数据结构默认是5M
  • 在shuffle的时候会有一个定时器,不定期的去估算这个内存结构的大小,当内存结构中的数据超过5M时,比如现在内存结构中的数据为5.01M,那么他会申请5.01*2-5=5.02M内存给内存数据结构。
  • 如果申请成功不会进行溢写,如果申请不成功,这时候会发生溢写磁盘。
  • 在溢写之前内存结构中的数据会进行排序分区
  • 然后开始溢写磁盘,写磁盘是以batch的形式去写,一个batch是1万条数据,
  • map task执行完成后,会将这些磁盘小文件合并成一个大的磁盘文件(有序),同时生成一个索引文件。
  • reduce task去map端拉取数据的时候,首先解析索引文件,根据索引文件再去拉取对应的数据。
  • 总结
  • 产生磁盘小文件的个数: 2*M(map task的个数)索引文件-和磁盘文件
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值