Spark Core基础知识:
1)Spark 是一种基于内存的快速、通用、可扩展的大数据分析计算引擎。
3)Spark部署模式:Local(本地)模式,Standalone(独立部署)模式,Yarn(集群)模式。
4)Spark 运行架构:
(1)Driver:
Spark 驱动器节点,用于执行 Spark 任务中的 main 方法。Driver 在 Spark 作业执行时主要负责:
➢ 将用户程序转化为作业(job)
➢ 在 Executor 之间调度任务(task)
➢ 跟踪 Executor 的执行情况
(2)Executor :
Spark Executor 是集群中工作节点(Worker)中的一个 JVM 进程,负责在 Spark 作业中运行具体任务(Task)。Executor 有两个核心功能:
➢ 负责运行组成 Spark 应用的任务,并将结果返回给驱动器进程 。
➢ 它们通过自身的块管理器(Block Manager)为用户程序中要求缓存的 RDD 提供内存式存储。
(3)master:管理集群和节点,不参与计算。
(4)worker:集群中工作节点,不参与计算,和master汇报。
(5)spark context:控制整个application的生命周期,包括dag sheduler和task scheduler等组件。
(6)client:用户提交程序的入口。
5)Spark 应用程序提交到 Yarn 环境中执行的时候,一般会有两种部署执行的方式:Client(主要用于测试)和 Cluster。两种模式主要区别在于:Driver 程序的运行节点位置。Yarn Cluster 模式Driver 程序会运行在 Master 进程内部,Yarn Client 模式 Driver 程序不会运行在这个 Master 进程内部,而是运行在本地,只是通过 Master 来申请资源。
Spark执行流程(Yarn Cluster 模式):
➢ 任务提交后向 ResourceManager 申请启动ApplicationMaster。
➢ 随后 ResourceManager 分配 container,在合适的 NodeManager 上启动 ApplicationMaster,此时的 ApplicationMaster 就是 Driver。
➢ Driver 启动后向 ResourceManager 申请 Executor 内存,ResourceManager 接到ApplicationMaster 的资源申请后会分配 container,然后在合适的 NodeManager 上启动Executor 进程。
➢ Executor 进程启动后会向 Driver 反向注册,Executor 全部注册完成后 Driver 开始执行main 函数,创建spark context。
➢ 之后执行到 Action 算子时,触发一个 Job,并根据宽依赖开始划分 stage,每个 stage 生成对应的 TaskSet,之后将 task 分发到各个 Executor 上执行。
6) Spark三大数据结构:
RDD : 弹性分布式数据集,累加器:分布式共享只写变量,广播变量:分布式共享只读变量。
7)RDD特点:
(1)弹性:
存储的弹性:内存与磁盘的自动切换;
容错的弹性:数据丢失可以自动恢复;
计算的弹性:计算出错重试机制;
分片的弹性:可根据需要重新分片。
(2)分布式:数据存储在大数据集群不同节点上 。
(3)数据集:RDD 封装了计算逻辑,并不保存数据 。
(4)数据抽象:RDD 是一个抽象类,需要子类具体实现 。
(5)不可变:RDD 封装了计算逻辑,是不可以改变的,想要改变,只能产生新的 RDD,在新的 RDD 里面封装计算逻辑 。
(6)可分区、并行计算 。
8)从计算的角度, RDD算子以外的代码都是在 Driver 端执行, 算子里面的代码都是在 Executor端执行。
9)RDD 依赖关系:
RDD 窄依赖:窄依赖表示每一个父(上游)RDD 的 Partition 最多被子(下游)RDD 的一个 Partition 使用。
RDD 宽依赖:宽依赖表示同一个父(上游)RDD 的 Partition 被多个子(下游)RDD 的 Partition 依赖,本质上是 Shuffle。
10)RDD Cache 缓存:
RDD 通过 Cache 或者 Persist 方法将前面的计算结果缓存,默认情况下会把数据缓存在 JVM 的堆内存中。但是并不是这两个方法被调用时立即缓存,而是触发后面的 action 算子时,该 RDD 将会被缓存在计算节点的内存中,并供后面重用。
11)RDD CheckPoint 检查点:
检查点其实就是通过将 RDD 中间结果写入HDFS,由于血缘依赖过长会造成容错成本过高,这样就不如在中间阶段做检查点容错,如果检查点之后有节点出现问题,可以从检查点开始重做血缘,减少了开销。对 RDD 进行 checkpoint 操作并不会马上被执行,必须执行 Action 操作才能触发。
12)缓存和检查点区别:
(1)Cache 缓存只是将数据保存起来,不切断血缘依赖。Checkpoint 检查点切断血缘依赖。
(2)Cache 缓存的数据通常存储在磁盘、内存等地方,可靠性低。Checkpoint 的数据通常存储在 HDFS 等容错、高可用的文件系统,可靠性高。
13)累加器:
累加器用来把 Executor 端变量信息聚合到 Driver 端。在 Driver 程序中定义的变量,在Executor 端的每个 Task 都会得到这个变量的一份新的副本,每个 task 更新这些副本的值后,传回 Driver 端进行 merge。
14)广播变量:
广播变量用来高效分发较大的对象。向所有工作节点发送一个较大的只读值,以供一个或多个 Spark 操作使用。比如,如果你的应用需要向所有节点发送一个较大的只读查询表,广播变量用起来都很顺手。
15)在 Spark 中,一个 task 对应一个分区,通常不会跨分区操作数据。但如果遇到 reduceByKey 等操作,Spark 必须从所有分区读取数据,并查找所有键的所有值,然后汇总在一起以计算每个键的最终结果 ,这称为 Shuffle。Shuffle 是一项昂贵的操作,因为它通常会跨节点操作数据,这会涉及磁盘 I/O,网络 I/O,和数据序列化。某些 Shuffle 操作还会消耗大量的堆内存,因为它们使用堆内存来临时存储需要网络传输的数据。由于 Shuffle 操作对性能的影响比较大,所以需要特别注意使用,以下操作都会导致 Shuffle:
(1)涉及到重新分区操作: 如 repartition 和 coalesce;
(2)所有涉及到 ByKey 的操作:如 groupByKey 和 reduceByKey,但 countByKey 除外;
(3)联结操作:如 cogroup 和 join。
16) 通常来说,Spark与MapReduce相比,Spark运行效率更高。请说明效率更高来源于Spark内置的哪些机制?
区别在于:
(1)MapReduce通常需要将计算的中间结果写入磁盘,然后还要读取磁盘,从而导致了频繁的磁盘IO。Spark则不需要将计算的中间结果写入磁盘,这得益于Spark的RDD(弹性分布式数据集,很强大)和DAG(有向无环图),其中DAG记录了job的stage以及在job执行过程中父RDD和子RDD之间的依赖关系。中间结果能够以RDD的形式存放在内存中,且能够从DAG中恢复,大大减少了磁盘IO。
(2)MapReduce在Shuffle时需要花费大量时间进行排序,排序在MapReduce的Shuffle中似乎是不可避免的;Spark在Shuffle时则只有部分场景才需要排序,支持基于Hash的分布式聚合,更加省时;
(3 )多进程模型 vs 多线程模型的区别:
MapReduce采用了多进程模型,而多进程模型的好处是便于细粒度控制每个任务占用的资源,但每次任务的启动都会消耗一定的启动时间,每次启动都需要重新申请资源,消耗了不必要的时间。
Spark采用了多线程模型,通过复用线程池中的线程来减少启动、关闭task所需要的开销。(多线程模型也有缺点,由于同节点上所有任务运行在一个进程中,因此,会出现严重的资源争用)
17)spark如何保证宕机迅速恢复?
(1)适当增加spark standby master(高可用)。
(2)编写shell脚本,定期检测master状态,出现宕机后对master进行重启操作。
18)hadoop和spark的相同点和不同点?
Hadoop底层使用MapReduce计算架构,只有map和reduce两种操作,表达能力比较欠缺,而且在MR过程中会重复的读写hdfs,造成大量的磁盘io读写操作,所以适合高时延环境下批处理计算的应用;
Spark是基于内存的分布式计算架构,提供更加丰富的数据集操作类型,主要分成转化操作和行动操作,包括map、reduce、filter、flatmap、groupbykey、reducebykey、union和join等,数据分析更加快速,所以适合低时延环境下计算的应用;
spark与hadoop最大的区别在于迭代式计算模型。基于mapreduce框架的Hadoop主要分为map和reduce两个阶段,两个阶段完了就结束了,所以在一个job里面能做的处理很有限;spark计算模型是基于内存的迭代式计算模型,可以分为n个阶段,根据用户编写的RDD算子和程序,在处理完一个阶段后可以继续往下处理很多个阶段,而不只是两个阶段。所以spark相较于mapreduce,计算模型更加灵活,可以提供更强大的功能。
但是spark也有劣势,由于spark基于内存进行计算,虽然开发容易,但是真正面对大数据的时候,在没有进行调优的情况下,可能会出现各种各样的问题,比如OOM内存溢出等情况,导致spark程序可能无法运行起来,而mapreduce虽然运行缓慢,但是至少可以慢慢运行完。
19)RDD持久化原理?
spark非常重要的一个功能特性就是可以将RDD持久化在内存中。调用cache()和persist()方法即可。cache()和persist()的区别在于,cache()是persist()的一种简化方式,cache()的底层就是调用persist()的无参版本persist(MEMORY_ONLY),将数据持久化到内存中。
如果需要从内存中清除缓存,可以使用unpersist()方法。RDD持久化是可以 手动选择不同的策略的。在调用persist()时传入对应的StorageLevel即可。
20)RDD机制理解吗?
RDD是Spark的一种数据结构,全称为弹性分布式数据集。所有spark算子都是基于rdd来执行的,不同的场景会有不同的rdd实现类,但是都可以进行互相转换。rdd执行过程中会形成dag图,然后形成lineage(血缘关系)保证容错性等。它是被分区的,每个分区分布在集群中的不同结点上,从而让RDD中的数据可以被并行操作(分布式数据集)。RDD的数据默认存放在内存中,但是当内存资源不足时,spark会自动将RDD数据写入磁盘。
21)Spark streaming以及基本工作原理?
Spark streaming是spark core API的一种扩展,可以用于进行大规模、高吞吐量、容错的实时数据流的处理。Spark streaming内部的基本工作原理是:接受实时输入数据流,然后将数据拆分成batch,比如每收集一秒的数据封装成一个batch(一个采集周期),然后将每个batch交给spark的计算引擎进行处理,最后会生产处一个结果数据流,其中的数据也是一个一个的batch组成的。
22) DStream以及基本工作原理?
DStream是spark streaming提供的一种高级抽象,代表了一个持续不断的数据流。
DStream可以通过输入数据源来创建,比如Kafka、flume等,也可以通过其他DStream的高阶函数来创建,比如map、reduce、join和window等。
23)Spark主备切换机制原理知道吗?
Master实际上可以配置两个,Spark原生的standalone模式是支持Master主备切换的。当Active Master节点挂掉以后,我们可以将Standby Master切换为Active Master。
Spark Master主备切换可以基于两种机制,一种是基于文件系统的,一种是基于ZooKeeper的。
基于文件系统的主备切换机制,需要在Active Master挂掉之后手动切换到Standby Master上;
而基于Zookeeper的主备切换机制,可以实现自动切换Master。
24 ) spark解决了hadoop的哪些问题?
(1)MR:抽象层次低,需要使用手工代码来完成程序编写,使用上难以上手;
Spark:Spark采用RDD计算模型,简单容易上手。
(2)MR:只提供map和reduce两个操作,表达能力欠缺;
Spark:Spark采用更加丰富的算子模型,包括map、flatmap、groupbykey、reducebykey等;
(3)MR:一个job只能包含map和reduce两个阶段,复杂的任务需要包含很多个job,这些job之间的管理以来需要开发者自己进行管理;
Spark:Spark中一个job可以包含多个转换操作,在调度时可以生成多个stage;
(4)MR:中间结果存放在磁盘中;
Spark:Spark的中间结果一般存在内存中,只有当内存不够了,才会存入本地磁盘;
(5)MR:只有等到所有的map task执行完毕后才能执行reduce task;
Spark:Spark中分区相同的转换构成流水线在一个task中执行,分区不同的需要进行shuffle操作,被划分成不同的stage需要等待前面的stage执行完才能执行。
(6)MR:只适合batch批处理,时延高,对于交互式处理和实时处理支持不够;
Spark:Spark streaming可以将流拆成时间间隔的batch进行处理,实时计算。
25) 数据倾斜的产生和解决办法?
数据倾斜指某一个或者某几个partition的数据特别大,导致这几个partition上的计算需要耗费相当长的时间。
在spark中同一个job划分成多个stage,这些stage之间是串行执行的,而一个stage里面的多个task是可以并行执行,task数目由partition数目决定,如果一个partition的数目特别大,那么导致这个task执行时间很长,导致接下来的stage无法执行,从而导致整个job执行变慢。
避免数据倾斜,一般是要选用合适的key,或者自己定义相关的partitioner,通过加盐或者哈希值来拆分这些key,从而将这些数据分散到不同的partition去执行。
如下算子会导致shuffle操作,是导致数据倾斜可能发生的关键点所在:groupByKey;reduceByKey;aggregaByKey;join;cogroup;
26)RDD中reduceBykey与groupByKey哪个性能好,为什么?
reduceByKey:reduceByKey会在结果发送至reducer之前会对每个mapper在本地进行merge,有点类似于在MapReduce中的combiner。这样做的好处在于,在map端进行一次reduce之后,数据量会大幅度减小,从而减小传输,保证reduce端能够更快的进行结果计算。
groupByKey:groupByKey会对每一个RDD中的value值进行聚合形成一个序列(Iterator),此操作发生在reduce端,所以势必会将所有的数据通过网络进行传输,造成不必要的浪费。同时如果数据量十分大,可能还会造成OutOfMemoryError。
所以在进行大量数据的reduce操作时候建议使用reduceByKey。不仅可以提高速度,还可以防止使用groupByKey造成的内存溢出问题。
27)Spark master HA主从切换过程不会影响到集群已有作业的运行,为什么?
不会的。因为程序在运行之前,已经申请过资源了,只需要driver和Executors通讯,不需要和master进行通讯的。
28)spark master使用zookeeper进行ha,有哪些源数据保存到Zookeeper里面?
spark通过这个参数spark.deploy.zookeeper.dir指定master元数据在zookeeper中保存的位置,包括Worker,Driver和Application以及Executors。standby节点要从zk中获得元数据信息,恢复集群运行状态,才能对外继续提供服务,作业提交,资源申请等,在恢复前是不能接受请求的。
29)Spark 如何做Stage划分? 如何优化?
总结一点: 当Spark 遇到宽依赖时会划分Stage 。
对于宽依赖来说,由于Shuffle的存在,只能在上游RDD 的Shuffle 处理结束后,才能开始接下来的计算,因此宽依赖作为Spark划分Stage的依据。
对于窄依赖来说,由于Partition之间的依赖关系是确定的,Partition的转换处理可以在同一个线程里完成,为了提高数据处理速度, 窄依赖被Spark划分到同一个执行阶段。
在一个Stage内部,每个Partition都会被分配一个计算任务(Task),这些Task是可以并行执行的。Stage之间根据依赖关系变成了一个大粒度的DAG,这个DAG的执行顺序也是从前向后的。也就是说,Stage只有在它是Stage的开端或者上游 Stage都已经执行结束后,才会执行。
优化方法:
由于宽依赖会进行Stage的划分并产生shuffle,而Shuffle操作由于涉及大量的网络传输,较为耗时,故需尽量避免使用会产生shuffle的算子,如reduceByKey, groupByKey, intersection等,可以使用其他的算子来代替。
30)请描述下Spark的Shuffle过程:
Shuffle阶段可进一步划分成三个子过程, 分别如下:
Shuffle Write:一批任务(ShuffleMapTask)将程序输出的临时数据并写到本地磁盘。由于每个任务产生的数据要被下一个阶段的每个任务读取一部分,因此存入磁盘时需对数据分区,分区可以使用Hash与Sort两种方法;
Shuffle Read:下一个阶段启动一批新任务(ResultTask),它们各自启动一些线程远程读取Shuffle Write产生的数据;
Aggregate:一旦数据被远程拷贝过来后,接下来需按照key将数据组织在一起,为后续计算做准备。
31)Spark小文件问题产生原因分析及处理方案:
使用sparkstreaming时,如果实时计算结果要写入到HDFS,那么不可避免的会遇到一个问题,那就是在默认情况下会产生非常多的小文件,这是由sparkstreaming的微批处理模式和DStream(RDD)的分布式(partition)特性导致的,sparkstreaming为每个partition启动一个独立的线程来处理数据,一旦文件输出到HDFS,那么这个文件流就关闭了,再来一个batch的parttition任务,就再使用一个新的文件流。
(1)增加batch大小:
batch越大,从外部接收的event就越多,内存积累的数据也就越多,那么输出的文件数也就回变少。但是此时延迟会比较大,不适合实时性要求高的场景。
(2)coalesce和repartition:
小文件的基数是:batch_number * partition_number,而第一种方法是减少batch_number,那么这种方法就是减少partition_number了,这个api不细说,就是减少初始的分区个数。
(3)SparkStreaming外部来处理:
在sparkstreaming外再启动定时的批处理任务来合并sparkstreaming产生的小文件。需要注意合并任务的时间划分,避免合并正在写入的sparkstreaming文件。
(4)自己调用foreach去append:
sparkstreaming提供的foreach这个outout类api,可以让我们自定义输出计算结果的方法。那么我们其实也可以利用这个特性,那就是每个batch在要写文件时,并不是去生成一个新的文件流,而是把之前的文件打开。考虑这种方法的可行性,首先,HDFS上的文件不支持修改,但是很多都支持追加,那么每个batch的每个partition就对应一个输出文件,每次都去追加这个partition对应的输出文件,这样也可以实现减少文件数量的目的。这种方法要注意的就是不能无限制的追加,当判断一个文件已经达到某一个阈值时,就要产生一个新的文件进行追加了。
32)Spark streamning和Storm比有什么区别:
Spark Streaming 与 Storm 都可以用于进行实时流计算。Spark Streaming 是基于 RDD 的,因此需要将一小段时间内的,比如1秒内的数据,收集起来,作为一个 RDD,然后再针对这个 batch 的数据进行处理。而 Storm 却可以做到每来一条数据,都可以立即进行处理和计算。因此,Spark Streaming 实际上严格意义上来说,只能称作准实时的流计算框架;而 Storm 是真正意义上的实时计算框架。
Storm 支持在分布式流式计算程序(Topology)在运行过程中,可以动态地调整并行度,从而动态提高并发处理能力。而 Spark Streaming 是无法动态调整并行度的。
通常在对实时性要求特别高,而且实时数据量不稳定,比如在白天有高峰期的情况下,可以选择使用Storm。但是如果是对实时性要求一般,允许1秒的准实时处理,而且不要求动态调整并行度的话,选择Spark Streaming是更好的选择。
33)为什么要用Yarn来部署Spark?
因为 Yarn 支持动态资源配置。Standalone 模式只支持简单的固定资源分配策略,每个任务固定数量的 core,各 Job 按顺序依次分配资源,资源不够的时候就排队。这种模式比较适合单用户的情况,多用户的情境下,会有可能有些用户的任务得不到资源。
34)说说Spark的预写日志功能:
也叫 WriteAheadLogs,通常被用于数据库和文件系统中,保证数据操作的持久性。预写日志通常是先将操作写入到一个持久可靠的日志文件中,然后才对数据施加该操作,当加入施加该操作中出现异常,可以通过读取日志文件并重新施加该操作,从而恢复系统。
当 WAL 开启后,所有收到的数据同时保存到了容错文件系统的日志文件中,当 Spark Streaming 失败,这些接受到的数据也不会丢失。另外,接收数据的正确性只在数据被预写到日志以后接收器才会确认。已经缓存但还没有保存的数据可以在 Driver 重新启动之后由数据源再发送一次(经常问)。
这两个机制保证了数据的零丢失,即所有的数据要么从日志中恢复,要么由数据源重发。