Spark面试总结(1)

1.spark中的RDD

RDD(Resilient Distributed Dataset)叫做分布式数据集,是spark中最基本的数据抽象,它代表一个不可变,可分区,里面的元素可以并行计算的集合

RDD被表示为对象,通过对象上的方法调用来对RDD进行转换。经过一系列的transformations定义RDD之后,就可以调用actions触发RDD的计算,action可以是向应用程序返回结果(count, collect等),或者是向存储系统保存数据(saveAsTextFile等)。在Spark中,只有遇到action,才会执行RDD的计算(即延迟计算),这样在运行时可以通过管道的方式传输多个转换。

2.coalesce和repartition的区别

coalesce重新分区,可以选择是否进行shuffle过程。由参数shuffle: Boolean = false/true决定。
repartition实际上是调用的coalesce,默认是进行shuffle的。
减少分区允许不进行shuffle过程,但是增大分区需要。
所以coalesce可以在不进行shuffle的情况下减少分区,增大分区需要指定第二个参数为true
减少分区的应用场景:例如通过filter之后,有些分区数据量比较少,通过减少分区,防止数据倾斜
增大分区的应用场景:分区内数据量太大,通过增加分区提高并行度

3.spark中的宽窄依赖

窄依赖

父RDD和子RDD partition之间的关系是一对一的。或者父RDD一个partition只对应一个子RDD的partition情况下的父RDD和子RDD partition关系是多对一的。不会有shuffle的产生。父RDD的一个分区去到子RDD的一个分区。

宽依赖

RDD与子RDD partition之间的关系是一对多。会有shuffle的产生。父RDD的一个分区的数据去到子RDD的不同分区里面。

4.spark中如何划分stage

Spark任务会根据RDD之间的依赖关系,形成一个DAG有向无环图,DAG会提交给DAGScheduler,DAGScheduler会把DAG划分相互依赖的多个stage,划分依据就是宽窄依赖,遇到宽依赖就划分stage,每个stage包含一个或多个task,然后将这些task以taskSet的形式提交给TaskScheduler运行,stage是由一组并行的task组成

注意:

park程序中可以因为不同的action触发众多的job,一个程序中可以有很多的job,每一个job是由一个或者多个stage构成的,后面的stage依赖于前面的stage,也就是说只有前面依赖的stage计算完毕后,后面的stage才会运行;

stage 的划分标准就是宽依赖:何时产生宽依赖就会产生一个新的stage,例如reduceByKey,groupByKey,join的算子,会导致宽依赖的产生;

5.DAG

DAG,有向无环图,说白了,就是一个由顶点和有方向性的边构成的图中,从任意一个顶点出发,并且不会回到原点,它为每个spark job计算出有多少个stage任务阶段,通常根据shuffle来划分stage,如reduceByKey,groupByKey等涉及到shuffle的transformation就会产生新的stage ,然后将每个stage划分为具体的一组任务,以TaskSets的形式提交给底层的任务调度模块来执行,其中不同stage之前的RDD为宽依赖关系,TaskScheduler任务调度模块负责具体启动任务,监控和汇报任务运行情况。

6.Job的生成

在编写的一个程序中只要有一个行动算子的出现例如:collect ,就会生成一个job。然后向DAGScheduler提交job,如果driver程序后面还有别的action,那么其他action也会对应生成相应的job,所以,driver端有多少action就会提交多少job,这可能就是为什么spark将driver程序称为application而不是job 的原因。每一个job可能会包含一个或者多个stage,最后一个stage生成result,在提交job 的过程中,DAGScheduler会首先从后往前划分stage,划分的标准就是宽依赖,一旦遇到宽依赖就划分,然后先提交没有父阶段的stage,并在提交过程中,计算该stage的task数目以及类型,并提交具体的task,在这些无父阶段的stage提交完之后,依赖该stage 的stage才会提交

7.RDD缓存

Spark可以使用 persist 和 cache 方法将任意 RDD 缓存到内存、磁盘文件系统中。缓存是容错的,如果一个 RDD 分片丢失,可以通过构建它的 transformation自动重构。被缓存的 RDD 被使用的时,存取速度会被大大加速。一般的executor内存60%做 cache, 剩下的40%做task。

Spark中,RDD类可以使用cache() 和 persist() 方法来缓存。cache()是persist()的特例,将该RDD缓存到内存中。而persist可以指定一个StorageLevel。StorageLevel的列表可以在StorageLevel 伴生单例对象中找到。

8.spark的有几种部署模式

8.1.本地模式

Spark不一定非要跑在hadoop集群,可以在本地,起多个线程的方式来指定。将Spark应用以多线程的方式直接运行在本地,一般都是为了方便调试,本地模式分三类

local:只启动一个executor

local[k]:启动k个executor

local:启动跟cpu数目相同的 executor

8.2standalone模式

分布式部署集群, 自带完整的服务,资源管理和任务监控是Spark自己监控,这个模式也是其他模式的基础

8.3Spark on yarn模式

分布式部署集群,资源和任务监控交给yarn管理,但是目前仅支持粗粒度资源分配方式,包含cluster和client运行模式,cluster适合生产,driver运行在集群子节点,具有容错功能,client适合调试,dirver运行在客户端

9.spark中worker 的主要工作

管理当前节点内存,CPU的使用情况,接受master发送过来的资源指令,通过executorRunner启动程序分配任务,worker就类似于包工头,管理分配新进程,做计算的服务,相当于process服务,需要注意的是

  1. worker会不会汇报当前信息给master?worker心跳给master主要只有workid,不会以心跳的方式发送资源信息给master,这样master就知道worker是否存活,只有故障的时候才会发送资源信息;

  2. worker不会运行代码,具体运行的是executor,可以运行具体application斜的业务逻辑代码,操作代码的节点,不会去运行代码。

10.hadoop和spark的shuffle相同和差异

10.1 同

都是将 mapper(Spark 里是 ShuffleMapTask)的输出进行 partition,不同的 partition 送到不同的 reducer(Spark 里 reducer 可能是下一个 stage 里的 ShuffleMapTask,也可能是 ResultTask)。Reducer 以内存作缓冲区,边 shuffle 边 aggregate 数据,等到数据 aggregate 好以后进行 reduce() (Spark 里可能是后续的一系列操作)。

10.2 异

  1. Hadoop的有一个Map完成,Reduce便可以去拉取数据了,不必等到所有Map任务完成,而Spark的必须等到父stage完成,也就是父stage的map操作全部完成才能去拉取数据。

  2. Hadoop的Reduce要等到拉取完全部数据,才将数据传入reduce函数进行聚合,而spark是一边拉取一边聚合。

11.spark组件

  1. master:管理集群和节点,不参与计算。

  2. worker:计算节点,进程本身不参与计算,和master汇报。

  3. Driver:运行程序的main方法,创建spark context对象。

  4. spark context:控制整个application的生命周期,包括dagsheduler和task scheduler等组件。

  5. client:用户提交程序的入口。

12.spark工作机制

  1. spark-submit 提交代码,执行 new SparkContext(),在 SparkContext 里构造 DAGSchedulerTaskScheduler
  2. TaskScheduler 会通过后台的一个进程,连接 Master,向 Master 注册 Application。
  3. Master 接收到 Application 请求后,会使用相应的资源调度算法,在 Worker 上为这个 Application 启动多个 Executer。
  4. Executor 启动后,会自己反向注册到 TaskScheduler 中。 所有 Executor 都注册到 Driver 上之后,SparkContext 结束初始化,接下来往下执行我们自己的代码。
  5. 每执行到一个 Action,就会创建一个 Job。Job 会提交给 DAGScheduler。
  6. DAGScheduler 会将 Job划分为多个 stage,然后每个 stage 创建一个 TaskSet。
  7. TaskScheduler 会把每一个 TaskSet 里的 Task,提交到 Executor 上执行。
  8. Executor 上有线程池,每接收到一个 Task,就用 TaskRunner 封装,然后从线程池里取出一个线程执行这个 task。(TaskRunner 将我们编写的代码,拷贝,反序列化,执行 Task,每个 Task 执行 RDD 里的一个 partition)

13.collect是什么

driver通过collect把集群中各个节点的内容收集过来汇总成结果,collect返回结果是Array类型的,collect把各个节点上的数据抓过来,抓过来数据是Array型,collect对Array抓过来的结果进行合并,合并后Array中只有一个元素,是tuple类型(KV类型的)的。

14.map与flatMap的区别

map:对RDD每个元素转换,文件中的每一行数据返回一个数组对象

flatMap:对RDD每个元素转换,然后再扁平化将所有的对象合并为一个对象,文件中的所有行数据仅返回一个数组对象,会抛弃值为null的值

15.Spark 中算子的使用

在我们的开发过程中,能避免则尽可能避免使用 reduceByKey、join、distinct、repartition 等会进行 shuffle 的算子,尽量使用 map 类的非 shuffle 算子。这样的话,没有 shuffle 操作或者仅有较少 shuffle 操作的 Spark 作业,可以大大减少性能开销。

16.Spark 优点

  1. 更高的性能。因为数据被加载到集群主机的分布式内存中。数据可以被快速的转换迭代,并缓存用以后续的频繁访问需求。在数据全部加载到内存的情况下,Spark可以比Hadoop快100倍,在内存不够存放所有数据的情况下快hadoop10倍。

  2. 通过建立在Java,Scala,Python,SQL(应对交互式查询)的标准API以方便各行各业使用,同时还含有大量开箱即用的机器学习库。

  3. 与现有Hadoop 1和2.x(YARN)生态兼容,因此机构可以无缝迁移。

  4. 方便下载和安装。方便的shell(REPL: Read-Eval-Print-Loop)可以对API进行交互式的学习。

  5. 借助高等级的架构提高生产力,从而可以讲精力放到计算上。

17.MapReduce和Spark的差异

原理上:

  1. MapReduce:基于磁盘的大数据批量处理系统

  2. Spark:基于RDD(弹性分布式数据集)数据处理,显示将RDD数据存储到磁盘和内存中。

模型上:

1.MapReduce可以处理超大规模的数据,适合日志分析挖掘等较少的迭代的长任务需求,结合了数据的分布式的计算。

  1. Spark:适合数据的挖掘,机器学习等多轮迭代式计算任务。

总结:

 1)基于内存计算,减少低效的磁盘交互;  

2)高效的调度算法,基于DAG;

3)容错机制Linage,精华部分就是DAG和Lingae

18.spark中的数据倾斜

1.什么是数据倾斜:

因为task是 并发执行的,所以有的task执行快,有的执行慢,或者等很长时间给你个提示说没内存了,导致的执行失败

2.原因:

数据问题

  • 1、key本身分布不均衡(包括大量的key为空)

  • 2、key的设置不合理

spark使用的问题

  • 1、shuffle时的并发度不够

  • 2、计算方式有误

3.造成的后果

  • 1、spark中的stage的执行时间受限于最后那个执行完成的task,因此运行缓慢的任务会拖垮整个程序的运行速度(分布式程序运行的速度是由最慢的那个task决定的)。

  • 2、过多的数据在同一个task中运行,将会把executor撑爆。

4.如何避免

发现数据倾斜的时候,不要急于提高executor的资源,修改参数或是修改程序,首先要检查数据本身,是否存在异常数据。找出异常的key

数据问题

如果任务长时间卡在最后最后1个(几个)任务,首先要对key进行抽样分析,判断是哪些key造成的。 选取key,对数据进行抽样,统计出现的次数,根据出现次数大小排序取出前几个。经过分析,倾斜的数据主要有以下三种情况:

  • 1、null(空值)或是一些无意义的信息()之类的,大多是这个原因引起。

  • 2、无效数据,大量重复的测试数据或是对结果影响不大的有效数据。

  • 3、有效数据,业务导致的正常数据分布。

  • 第1,2种情况,直接对数据进行过滤即可(因为该数据对当前业务不会产生影响)。

  • 第3种情况则需要进行一些特殊操作,常见的有以下几种做法

  • (1) 隔离执行,将异常的key过滤出来单独处理,最后与正常数据的处理结果进行union操作。

  • (2) 对key先添加随机值,进行操作后,去掉随机值,再进行一次操作。

  • (3) 使用reduceByKey 代替 groupByKey(reduceByKey用于对每个key对应的多个value进行merge操作,最重要的是它能够在本地先进行merge操作,并且merge操作可以通过函数自定义.)

  • (4) 使用map join。

Spark操作问题

    • 提高shuffle并行度
      • dataFrame和sparkSql可以设置spark.sql.shuffle.partitions参数控制shuffle的并发度,默认为200。
    • rdd操作可以设置spark.default.parallelism控制并发度,默认参数由不同的Cluster Manager控制。

    • 局限性: 只是让每个task执行更少的不同的key。无法解决个别key特别大的情况造成的倾斜,如果某些key的大小非常大,即使一个task单独执行它,也会受到数据倾斜的困扰。

    • 使用map join 代替reduce join

19.Spark streamning特点

Spark Streaming 是基于 RDD 的,因此需要将一小段时间内的,比如1秒内的数据,收集起来,作为一个 RDD,然后再针对这个 batch 的数据进行处理。Spark Streaming 是无法动态调整并行度。流式处理完的数据,可以立即进行各种map、reduce转换操作,可以立即使用sql进行查询,甚至可以立即使用machine learning或者图计算算法进行处理。

注意:

  • 只要一个StreamingContext启动之后,就不能再往其中添加任何计算逻辑了。

  • 一个StreamingContext停止之后,是肯定不能重启的。调用stop()之后,不能再调用start()

  • 一个JVM同时只能有一个StreamingContext启动(和SparkContext一样)。在应用程序中,不能创建两个StreamingContext。

  • 调用stop()方法时,会同时停止内部的SparkContext,如果希望后面继续使用SparkContext创建其他类型的Context,比如SQLContext,可以用stop(false)

  • 一个SparkContext可以创建多个StreamingContext,只要上一个先用stop(false)停止,再创建下一个即可。

20.Spark中的血统

RDD是弹性分布式数据集,是Spark中最基本的数据抽象,代表一个不可变、可分区、里面的元素可并行计算 的集合。

它提供了一个抽象的数据模型,将具体的应用逻辑表达为一系列转换操作(函数)。另外不同RDD之间的转换操作之间还可以形成依赖关系,进而实现管道化,从而避免了中间结果的存储,大大降低了数据复制、磁盘IO和序列化开销,并且还提供了更多的API(map/reduec/filter/groupBy…)

RDD 的 lineage 记录的是粗颗粒度的特定数据转换(transformation)操作(filter, map, join etc.)行为。当这个 RDD 的部分分区数据丢失时,它可以通过 lineage 获取足够的信息来重新运算和恢复丢失的数据分区。这种粗颗粒的数据模型,限制了 Spark 的运用场合,但同时相比细颗粒度的数据模型,也带来了性能的提升。

21.RDD共享变量

在应用开发中,一个函数被传递给Spark操作(例如map和reduce),在一个远程集群上运行,它实际上操作的是这个函数用到的所有变量的独立拷贝。这些变量会被拷贝到每一台机器。通常看来,在任务之间中,读写共享变量显然不够高效。然而,Spark还是为两种常见的使用模式,提供了两种有限的共享变量:广播变量和累加器

21.1广播变量(Broadcast Variables)

  • 广播变量缓存到各个节点的内存中,而不是每个 Task

  • 广播变量被创建后,能在集群中运行的任何函数调用

  • 广播变量是只读的,不能在被广播后修改

  • 对于大数据集的广播, Spark 尝试使用高效的广播算法来降低通信成本

  • val broadcastVar = sc.broadcast(Array(1, 2, 3))方法参数中是要广播的变量

21.2 累加器

累加器只支持加法操作,可以高效地并行,用于实现计数器和变量求和。Spark 原生支持数值类型和标准可变集合的计数器,但用户可以添加新的类型。只有驱动程序才能获取累加器的值

22.Spark 调优

参数调优

  • num-executors:设置Spark作业总共要用多少个Executor进程来执行

  • executor-memory:设置每个Executor进程的内存

  • executor-cores:设置每个Executor进程的CPU core数量

  • driver-memory:设置Driver进程的内存

  • spark.default.parallelism:设置每个stage的默认task数量

开发调优

  1. 避免创建重复的RDD

  2. 尽可能复用同一个RDD

  3. 对多次使用的RDD进行持久化

  4. 尽量避免使用shuffle类算子

  5. 使用map-side预聚合的shuffle操作

  6. 使用高性能的算子

23.Spark实现TopN

  • 方法1:

    (1)按照key对数据进行聚合(groupByKey)

    (2)将value转换为数组,利用scala的sortBy或者sortWith进行排序(mapValues)

    注意:当数据量太大时,会导致OOM

  • 方法2:

    (1)取出所有的key

    (2)对key进行迭代,每次取出一个key利用spark的排序算子进行排序

  • 方法3:

    (1)自定义分区器,按照key进行分区,使不同的key进到不同的分区

    (2)对每个分区运用spark的排序算子进行排序

24.RDD有几种操作类型

  • transformation,rdd由一种转为另一种rdd

  • action

  • cronroller,crontroller是控制算子,cache,persist,对性能和效率的有很好的支持三种类型

25.RDD的checkpoint

RDD的缓存能够在第一次计算完成后,将计算结果保存到内存、本地文件系统中。通过缓存,Spark避免了RDD上的重复计算,能够极大地提升计算速度。但是,如果缓存丢失了,则需要重新计算。如果计算特别复杂或者计算耗时特别多,那么缓存丢失对于整个Job的效率有很大影响,为了避免缓存丢失重新计算带来的开销,Spark又引入了检查点(checkpoint)机制。

缓存是在计算结束后,直接将计算结果通过用户定义的存储级别(存储级别定义了缓存存储的介质,现在支持内存、本地文件系统和Tachyon)写入不同的介质。而检查点不同,它是在计算完成后,重新建立一个Job来计算。为了避免重复计算,推荐 先将RDD缓存,这样就能保证检查点的操作可以快速完成。

26.RDD的弹性表现在哪?

  • 自动的进行内存和磁盘的存储切换;

  • 基于Lingage的高效容错;

  • task如果失败会自动进行特定次数的重试;

  • stage如果失败会自动进行特定次数的重试,而且只会计算失败的分片;

  • checkpoint和persist,数据计算之后持久化缓存

  • 数据调度弹性,DAG TASK调度和资源无关

  • 数据分片的高度弹性,a.分片很多碎片可以合并成大的,b.par

你可能感兴趣的:(Spark面试,大数据,spark)